Skip to content

fix(engine): resolve per-source power in each-X-deals-damage clauses - #7322

Merged
matthewevans merged 2 commits into
phase-rs:mainfrom
CodeOptimist:fix/bartz-and-boko
Aug 13, 2026
Merged

fix(engine): resolve per-source power in each-X-deals-damage clauses#7322
matthewevans merged 2 commits into
phase-rs:mainfrom
CodeOptimist:fix/bartz-and-boko

Conversation

@CodeOptimist

@CodeOptimist CodeOptimist commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the mis-parse of the filter-source own-power damage class — "each you control deals damage equal to its power to " (Bartz and Boko's ETB trigger). The clause fell through try_parse_each_source_deals_damage's Fixed-only amount guard, dropping the "each you control" subject and mis-parsing to a single ability-sourced DealDamage whose Power { Anaphoric } amount resolved against the trigger source instead of each batch member. The fix extends Effect::EachSourceDealsDamage.amount to per-source resolution via a new ObjectScope::BatchSource (CR 120.1), resolves the amount per source id (live + LKI, CR 113.7a), and rebinds the clause's deferred "its" pronoun to the per-batch-source scope at the each-source intercept.

Files changed

  • crates/engine/src/types/ability.rsObjectScope::BatchSource variant; EachSourceDealsDamage.amount doc
  • crates/engine/src/game/quantity.rsQuantityContext.damage_source field; quantity_expr_contains_scope; resolve_quantity_with_targets_and_damage_source; BatchSource arms at all ObjectScope match sites; damage_source: None threading (15 construction sites)
  • crates/engine/src/game/effects/deal_damage.rs — per-source amount resolution in resolve_each_source_deals_damage (simultaneous-batch/stash paths unchanged)
  • crates/engine/src/parser/oracle_effect/subject.rs — guard replaced with structural anaphor detection + rebind; fail-closed rider gate (random recipient, tapped this way sources); flips the old negative test; new parser tests; 10-card class comment
  • crates/engine/src/game/ability_rw.rs, ability_scan.rs, coverage.rs, effects/mod.rs, layers.rs, replacement.rs, restrictions.rs — additive BatchSource classification arms
  • crates/engine/tests/integration/bartz_and_boko_each_source_damage.rs (new) — discriminating runtime test
  • crates/engine/tests/integration/main.rs — mod line

Track

Developer

LLM

Model: deepseek-v4-flash-0731
Tier: Frontier
Thinking: max

Implementation method (required)

Method: /engine-implementer

CR references

120.1, 120.3, 120.4a, 120.4b, 120.6, 120.10, 704.5g, 113.7a, 208.1, 208.3, 608.2, 608.2c, 202.3, 109.4, 616.1; 303.4 (deferred attached-host fail-closed precedent). All verified in docs/MagicCompRules.txt.

Verification

  • Required checks ran clean, or the exact CI-owned alternative is stated below.

  • Gate A output below is for the current committed head.

  • Final review-impl below is clean for the current committed head.

  • Both anchors cite existing analogous code at the same seam.

  • cargo fmt --all — clean, no diff.

  • cargo clippy --all-targets -- -D warnings — clean (exit 0).

  • cargo test -p phase-engine — lib 18906 passed / 0 failed / 6 ignored; integration 4839 passed / 0 failed / 2 ignored; 21 bin + 9 doc tests passed / 0 failed.

  • ./scripts/gen-card-data.sh — exit 0; bartz and boko trigger effect = EachSourceDealsDamage, amount scope = BatchSource, no parse_warnings.

  • scripts/check-parser-combinators.sh c162191c9 — Gate G PASS; Gate A PASS (see below).

  • cargo coverage — exit 0; Bartz and Boko / Judgment of Alexander / Signature Slam supported=true, gap=0.

  • cargo semantic-audit — exit 0.

  • cargo test -p phase-engine --test integration bartz — 2 passed (discriminating runtime tests).

Gate A

Gate A PASS head=5fddcdcee12ad6cd838b20fb373945eb9bd0b170 base=c162191c91ff7aa2434c42baeb3fc9d60ce510a1

Anchored on

  • crates/engine/src/game/effects/deal_damage.rs:1425 (resolve_each_target_power_damage) — the EachDealsDamageEqualToPower sibling resolver: each chosen source's own power to a shared recipient (CR 120.1); the per-source amount resolution added here mirrors its per-source semantics.
  • crates/engine/src/game/quantity.rs:2051 (resolve_quantity_with_targets_and_recipient) — wrapper-shape precedent that resolve_quantity_with_targets_and_damage_source mirrors.

Final review-impl

Final review-impl PASS head=5fddcdcee12ad6cd838b20fb373945eb9bd0b170

Claimed parse impact

Bartz and Boko, Judgment of Alexander, Kamahl's Will, Master of the Wild Hunt, Moonlight Hunt, Nissa's Judgment, Sarkhan the Mad, Season's Beatings, Signature Slam, The Bears of Littjara. (8 parse to EachSourceDealsDamage with a BatchSource per-source amount; Season's Beatings and Master of the Wild Hunt's each-source clauses fail closed to Effect::Unimplemented because their riders are unrepresentable.)

Scope Expansion

None.

Validation Failures

None.

CI Failures

None.

Summary by CodeRabbit

  • New Features

    • Damage effects can now calculate separate amounts for each matching source, including that source’s power, toughness, counters, or mana value.
    • Composite expressions combining per-source values are supported.
    • Damage records correctly identify each contributing source.
  • Bug Fixes

    • Unsupported recipient or source conditions now fail safely instead of being silently ignored.
    • Effects with no matching sources correctly deal no damage.

Each-source damage clauses with an own-characteristic amount ("each other
Bird you control deals damage equal to its power to target creature an
opponent controls" — Bartz and Boko) fell through try_parse_each_source_
deals_damage's Fixed-only amount guard and mis-parsed to a single
ability-sourced DealDamage: the "each <filter> you control" subject was
dropped and Power{Anaphoric} resolved against the trigger source, not each
batch member.

Introduce ObjectScope::BatchSource (CR 120.1 per-iteration batch source) so
QuantityRef::Power { scope: BatchSource } types the per-source amount, thread
a QuantityContext.damage_source field + a per-source resolve wrapper
(resolve_quantity_with_targets_and_damage_source), and have
resolve_each_source_deals_damage resolve the amount per source id (live +
LKI fallback, CR 113.7a) inside the existing simultaneous-batch entries loop.
The parser guard now rebinds the clause's deferred "its" pronoun to
BatchSource via the structural rebind helper instead of rejecting it.

10-card class: Bartz and Boko, Judgment of Alexander, Kamahl's Will, Master
of the Wild Hunt, Moonlight Hunt, Nissa's Judgment, Sarkhan the Mad,
Season's Beatings, Signature Slam, The Bears of Littjara. Sources whose
riders the filter model cannot express fail closed to Unimplemented
(Season's Beatings' "random" recipient; Master of the Wild Hunt's "tapped
this way" source restriction) rather than silently degrading. Adds a
discriminating runtime cast-pipeline test (0/9 dies to sum 9, uniform/
ability-source 8 survives, Bartz excluded from attribution) plus parser and
resolver building-block tests pinning the class.
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c0e69b1-140a-436a-8dea-e0269ae98fd4

📥 Commits

Reviewing files that changed from the base of the PR and between 5fddcdc and 4ab57b9.

📒 Files selected for processing (4)
  • crates/engine/src/game/effects/deal_damage.rs
  • crates/engine/src/game/quantity.rs
  • crates/engine/src/parser/oracle_effect/subject.rs
  • crates/engine/tests/integration/bartz_and_boko_each_source_damage.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • crates/engine/src/game/effects/deal_damage.rs
  • crates/engine/tests/integration/bartz_and_boko_each_source_damage.rs
  • crates/engine/src/game/quantity.rs
  • crates/engine/src/parser/oracle_effect/subject.rs

📝 Walkthrough

Walkthrough

The PR adds ObjectScope::BatchSource for EachSourceDealsDamage. The parser binds source-dependent amounts to each batch member. Quantity resolution reads live or last-known information. Damage execution creates per-source entries and skips zero amounts.

Changes

BatchSource damage flow

Layer / File(s) Summary
BatchSource quantity contract
crates/engine/src/types/ability.rs, crates/engine/src/game/quantity.rs
Adds the BatchSource scope, per-source quantity context, recursive scope detection, and live/LKI resolution for counters, power, toughness, and mana value.
Oracle text lowering
crates/engine/src/parser/oracle_effect/subject.rs
Rebinds anaphoric damage amounts to BatchSource. Unsupported random recipients and tapped this way riders now produce Unimplemented.
Per-source damage execution
crates/engine/src/game/effects/deal_damage.rs, crates/engine/src/game/effects/mod.rs, crates/engine/src/game/layers.rs, crates/engine/src/game/replacement.rs, crates/engine/src/game/restrictions.rs
Resolves source-dependent amounts per batch member, skips zero results, preserves routing, and initializes or rejects damage_source where required.
Scope classification and integration coverage
crates/engine/src/game/ability_rw.rs, crates/engine/src/game/ability_scan.rs, crates/engine/src/game/coverage.rs, crates/engine/tests/integration/*
Updates read profiling and coverage classification. Adds integration tests for per-source power damage and damage-source attribution.

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

Mergeability Score: ⚪ Minimal · up to 4ab57

This PR corrects per-source damage parsing and resolution, with the supplied checks and runtime tests passing; no actionable merge-blocking risk remains after normal review.

Sequence Diagram(s)

sequenceDiagram
  participant OracleParser
  participant EachSourceDealsDamage
  participant QuantityResolver
  participant GameState
  OracleParser->>EachSourceDealsDamage: bind anaphoric amount to BatchSource
  EachSourceDealsDamage->>QuantityResolver: resolve amount for each source
  QuantityResolver->>GameState: read live object or LKI characteristics
  GameState-->>QuantityResolver: source quantity
  QuantityResolver-->>EachSourceDealsDamage: per-source amount
  EachSourceDealsDamage->>EachSourceDealsDamage: create non-zero damage entries
Loading

Possibly related PRs

  • phase-rs/phase#6220: Changes parser and runtime binding for damage amounts that reference power or toughness.
  • phase-rs/phase#6559: Adjusts parser handling for source-scoped quantity expressions and anaphoric bindings.
  • phase-rs/phase#6852: Changes damage-source-dependent quantity resolution for a different source scope.
🚥 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 main change: resolving per-source power for each-source damage effects.
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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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.

Actionable comments posted: 3

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

425-464: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Unify the scope-carrying QuantityRef enumeration to prevent drift.

ref_contains_scope lists Power, Toughness, ObjectManaValue, ObjectColorCount, ObjectNameWordCount, ObjectTypelineComponentCount, ManaSymbolsInManaCost, and CountersOn as the scope-carrying QuantityRef variants, then falls back to _ => false.

Two sibling functions enumerate almost the same set but omit CountersOn:

  • scope_is_resolution_only's inner match (inside quantity_expr_uses_resolution_only_object_scope, around line 395).
  • leaf_scope_missing's inner match (inside quantity_expr_missing_resolution_only_referent, around line 580).

If a future card uses CountersOn with a resolution-only scope (Anaphoric, Demonstrative, or BatchSource), quantity_expr_uses_resolution_only_object_scope and quantity_expr_missing_resolution_only_referent will not detect it, even though quantity_expr_contains_scope proves the detection is straightforward to add. Extract one shared list (or a small helper) of scope-carrying QuantityRef variants and reuse it across all three functions.

🤖 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/quantity.rs` around lines 425 - 464, Unify
scope-carrying QuantityRef classification across quantity_expr_contains_scope,
quantity_expr_uses_resolution_only_object_scope’s scope_is_resolution_only, and
quantity_expr_missing_resolution_only_referent’s leaf_scope_missing. Extract a
shared helper or exhaustive match that includes CountersOn and all existing
scoped variants, then reuse it so future QuantityRef additions cannot drift
between these checks.

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.

Inline comments:
In `@crates/engine/src/parser/oracle_effect/subject.rs`:
- Around line 7548-7576: Update both tests,
each_seasons_beatings_random_recipient_fails_closed and
each_master_of_the_wild_hunt_tapped_this_way_fails_closed, to assert the
specific guard-owned Unimplemented key in addition to matching
Effect::Unimplemented. Use the key emitted by the new fail-closed guards so the
tests prove these inputs reach the intended guards rather than passing through
the unrelated non-Fixed damage-amount fallback.

In `@crates/engine/tests/integration/bartz_and_boko_each_source_damage.rs`:
- Around line 80-82: Update both Bartz fixtures in the positive and negative
test setups to include Bartz’s printed Human and Bird subtypes after creating
the card, using the existing subtype/card-data configuration mechanism. Keep the
assertions unchanged so the tests exercise exclusion of the Bird subtype
candidate.
- Around line 33-35: Update the rules citation in the test module’s opening
comments to reference CR 608.2h for the last-known-information fallback,
retaining CR 113.7a only if needed to describe ability independence from its
source. Ensure the cited rule directly supports the source lookup behavior
implemented by the test.

---

Nitpick comments:
In `@crates/engine/src/game/quantity.rs`:
- Around line 425-464: Unify scope-carrying QuantityRef classification across
quantity_expr_contains_scope, quantity_expr_uses_resolution_only_object_scope’s
scope_is_resolution_only, and quantity_expr_missing_resolution_only_referent’s
leaf_scope_missing. Extract a shared helper or exhaustive match that includes
CountersOn and all existing scoped variants, then reuse it so future QuantityRef
additions cannot drift between these checks.
🪄 Autofix

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: d15bd8c3-ae45-4fa5-8db8-d1666fe331b7

📥 Commits

Reviewing files that changed from the base of the PR and between 552cf8f and 5fddcdc.

📒 Files selected for processing (13)
  • crates/engine/src/game/ability_rw.rs
  • crates/engine/src/game/ability_scan.rs
  • crates/engine/src/game/coverage.rs
  • crates/engine/src/game/effects/deal_damage.rs
  • crates/engine/src/game/effects/mod.rs
  • crates/engine/src/game/layers.rs
  • crates/engine/src/game/quantity.rs
  • crates/engine/src/game/replacement.rs
  • crates/engine/src/game/restrictions.rs
  • crates/engine/src/parser/oracle_effect/subject.rs
  • crates/engine/src/types/ability.rs
  • crates/engine/tests/integration/bartz_and_boko_each_source_damage.rs
  • crates/engine/tests/integration/main.rs

Comment thread crates/engine/src/parser/oracle_effect/subject.rs
Comment thread crates/engine/tests/integration/bartz_and_boko_each_source_damage.rs Outdated
@matthewevans matthewevans self-assigned this Aug 13, 2026
@matthewevans matthewevans added the bug Bug fix label Aug 13, 2026
@matthewevans

matthewevans commented Aug 13, 2026

Copy link
Copy Markdown
Member

Generated for head 4ab57b97b624d84739005717596735e01188e029.

Parse changes introduced by this PR · 10 card(s), 15 signature(s) (baseline: main 1c9343a8890a)

🟢 Added (9 signatures)

  • 2 cards · ➕ ability/each_source_unrepresentable_rider · added: each_source_unrepresentable_rider
    • Affected (first 3): Master of the Wild Hunt, Season's Beatings
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, kind=activated, recipient=player or planeswalker, sources=you control creature Dragon, timing=sorcery speed)
    • Affected (first 3): Sarkhan the Mad
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, recipient=opponent controls creature, sources=another you control Bird)
    • Affected (first 3): Bartz and Boko
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, recipient=opponent controls creature, sources=modified you control creature)
    • Affected (first 3): Signature Slam
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, recipient=triggering source, sources=1+ P1P1 counters you control creature)
    • Affected (first 3): Nissa's Judgment
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, recipient=triggering source, sources=commander you control creature)
    • Affected (first 3): Judgment of Alexander
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, recipient=triggering source, sources=power ≥4 you control creature)
    • Affected (first 3): The Bears of Littjara
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, recipient=triggering source, sources=you control Wolf or Werewolf creature)
    • Affected (first 3): Moonlight Hunt
  • 1 card · ➕ ability/EachSourceDealsDamage · added: EachSourceDealsDamage (amount=batch source's power, recipient=triggering source, sources=you control creature)
    • Affected (first 3): Kamahl's Will

🔴 Removed (6 signatures)

  • 4 cards · ➖ ability/DealDamage · removed: DealDamage (amount=self power, target=parent target)
    • Affected (first 3): Kamahl's Will, Moonlight Hunt, Nissa's Judgment (+1 more)
  • 2 cards · ➖ ability/DealDamage · removed: DealDamage (amount=self power, target=opponent controls creature)
    • Affected (first 3): Bartz and Boko, Signature Slam
  • 1 card · ➖ ability/DealDamage · removed: DealDamage (amount=self power, kind=activated, target=player or planeswalker, timing=sorcery speed)
    • Affected (first 3): Sarkhan the Mad
  • 1 card · ➖ ability/DealDamage · removed: DealDamage (amount=self power, target=another)
    • Affected (first 3): Season's Beatings
  • 1 card · ➖ ability/DealDamage · removed: DealDamage (amount=self power, target=creature)
    • Affected (first 3): Master of the Wild Hunt
  • 1 card · ➖ ability/DealDamage · removed: DealDamage (amount=self power, target=triggering source)
    • Affected (first 3): Judgment of Alexander

@matthewevans matthewevans left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Request changes — 2 test-discrimination blockers on 5fddcdcee12ad6cd838b20fb373945eb9bd0b170.

🔴 Blocker

  1. subject.rs:7548 — the Season's Beatings and Master of the Wild Hunt tests only match Effect::Unimplemented. Before this PR, their own-power amounts already fell through the unrelated non-Fixed rejection, so both tests still pass if the new random / tapped this way guards are removed. Assert the guard-owned key, name == "each_source_unrepresentable_rider", in both tests. This makes the fail-closed path discriminating.

  2. bartz_and_boko_each_source_damage.rs:80 and :135 — the two Bartz fixtures do not give Bartz its printed Human and Bird subtypes. It therefore never enters the candidate set, so the positive and zero-member tests can both pass if FilterProp::Another stops excluding it. Add .with_subtypes(vec!["Human", "Bird"]) to both fixtures; retain the existing assertions so they exercise the intended exclusion.

🟡 Correction

bartz_and_boko_each_source_damage.rs:33 attributes LKI lookup to CR 113.7a. The current official CR 608.2h is the direct authority: when information is required from a specific object no longer in its expected public zone, use its last known information. Cite CR 608.2h for the fallback (and retain CR 113.7a only for ability/source independence if that is the claim being made).

These current-head findings are independently reported by CodeRabbit and confirmed against the diff. The implementation’s parser/resolver seam otherwise looks appropriate; after the fixes, please let CI and the required current-head parse-diff artifact complete for a renewed review.

Recommendation: update this PR with the two discriminating fixtures and citation correction, then request re-review.

@matthewevans matthewevans removed their assignment Aug 13, 2026
…ng (review)

Follow-up to the each-source-damage fix (5fddcdc) addressing code review:

- subject.rs: the Season's Beatings ("random" recipient) and Master of the
  Wild Hunt ("tapped this way") fail-closed tests previously matched only
  `Effect::Unimplemented { .. }` — the same outcome as the pre-guard
  fallthrough, so both passed without the guards. Pin the guard-owned key
  `each_source_unrepresentable_rider` (via a const comparison) so the
  fail-closed path discriminates; neutralized-guard revert probe fails both.
- bartz integration tests: give Bartz its printed Human/Bird subtypes in
  both fixtures so he genuinely matches the "Bird" filter, making the
  `FilterProp::Another` "other" exclusion load-bearing (probes: dropping
  "other" with subtypes present fails both tests; without subtypes both
  pass regardless).
- CR annotations: the batch-member LKI fallback is CR 608.2h (effect reads
  a specific object no longer in its expected public zone -> last known
  information), not CR 113.7a (ability-source independence). Corrected the
  7 commit-added comment sites and the integration test module doc.
@matthewevans matthewevans self-assigned this Aug 13, 2026

@matthewevans matthewevans left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed current head 4ab57b9. The prior blockers are resolved: strict-failure parser fixtures now assert the exact unimplemented key, the Bartz runtime fixture makes Bartz a Human Bird so the “other” exclusion is real, and CR 608.2h correctly supports the LKI fallback. Manual trace confirms ObjectScope::BatchSource is rebound from the per-source anaphor, resolved per batch member, and preserved through replacement continuations. Required CI and parse-diff are current and clean; CodeRabbit’s current-head delta sweep found no new actionable finding. Its older classifier-drift nit remains nonblocking because this PR does not produce a CountersOn BatchSource card path.

@matthewevans
matthewevans added this pull request to the merge queue Aug 13, 2026
@matthewevans matthewevans removed their assignment Aug 13, 2026
Merged via the queue into phase-rs:main with commit 1f612b5 Aug 13, 2026
15 checks passed
@CodeOptimist
CodeOptimist deleted the fix/bartz-and-boko branch August 13, 2026 14:04
JacobWoodson added a commit to JacobWoodson/phase that referenced this pull request Aug 13, 2026
One conflict, in the import list of oracle_effect/subject.rs: this branch
added EffectScope for the broadcast ForceAttack arm while phase-rs#7326 / phase-rs#7322 /
phase-rs#7333 added ObjectScope. Both are needed; kept both.
@coderabbitai coderabbitai Bot mentioned this pull request Aug 15, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants