chore: update coverage stats and badges - #9
Merged
Conversation
matthewevans
enabled auto-merge (squash)
April 8, 2026 14:39
matthewevans
force-pushed
the
chore/update-coverage-badges
branch
from
April 8, 2026 14:49
58ef9f6 to
a1d4e9b
Compare
andriypolanski
pushed a commit
to andriypolanski/phase
that referenced
this pull request
Jul 10, 2026
…y (unit 3b, byte-safe subset) (phase-rs#5513) * refactor(parser): key OracleDocBuilder items by (first_line, start_byte, ordinal) (unit 3b-1) `OracleDocBuilder::items` was keyed `(first_line, ordinal_within_span)`. Two exact, NON-overlapping clauses on one physical line with the same `ordinal_within_span` pass `conflicts_with` (which rejects only OVERLAPPING sibling bytes) and then collide on the map key: `emit` returns `DuplicateItemPosition` and the second clause is lost. A `(first_line, ordinal)` key would also order same-line siblings by ordinal rather than by byte position, so an emitter assigning ordinals out of byte order would have `finish()` return them reversed and `lower_oracle_ir` would lower them reversed -- silently. Add `start_byte` to the key. Inert today (every item spans the whole document, so `start_byte == 0`), but unit 3b emits exact spans, at which point "Destroy target creature. It can't be regenerated." is two clauses on one line. Fixed before it can fire. Discriminating test: `two_exact_clauses_on_one_line_coexist_and_order_by_byte` emits the later clause first and asserts both coexist and come back in byte order. Watched go red against the reconstructed `(first_line, ordinal)` key: 18620 tests run, exactly 1 failed, and it was this test. * refactor(parser): typed AbilityIr shell replaces the effect-chain escape hatch (units 3b-2, 3b-3) The two effect-chain entry points, `parse_effect_chain` and `parse_effect_chain_with_context`, each opened with a hand-maintained stack of whole-body `try_parse_* -> return AbilityDefinition` bypasses, then lowered the IR and ran `finalize_effect_chain` + the owner-library anchor inline. Two latent hazards lived here: 1. The two stacks are NOT the same set. `parse_effect_chain` runs 8 bypasses; `parse_effect_chain_with_context` runs the same 8 as a strict prefix plus `try_parse_exile_pile_shuffle_cloak`. Duplicating them as two `if let` ladders invited silent divergence. This is now typed data: `ChainLoweringMode { Standalone, WithContext }` (exhaustive, no `_` arm, no `Default`), dispatched by one `try_parse_chain_bypass`. The asymmetry is preserved byte-for-byte -- it is a suspected-accidental pre-existing quirk (ISSUES.md phase-rs#9), and a parity migration never absorbs a bug fix. 2. `try_parse_balance_equalization` sets `sub_link = SequentialSibling` on its ROOT def (CR 608.2e: three independent equalize steps, each resolving even when an optional parent is declined). No `ClauseIr`/`EffectChainIr` field can express a root `sub_link` -- `lower_effect_chain_ir` derives it from the previous clause boundary, and the root has none, so it is unconditionally `ContinuationStep`. Converting that bypass to return a bare `EffectChainIr` would silently flip its semantics. `AbilityShellIr` is the typed home for exactly the root fields no clause can hold; today that is `sub_link` alone (verified by auditing the return expressions -- not field names -- of all nine bypasses: they set only kind/effect/sub_ability/duration/player_scope, all clause-expressible, plus balance's root sub_link). `lower_ability_ir` is now the single authority for the post-parse sequence: lower the chain, finalize, anchor, then apply the shell. `finalize` and the anchor stay here rather than in `lower_effect_chain_ir` so the ~7 production callers that lower a chain without being a whole ability body are unaffected. Parity: 191 snapshots byte-identical (0 .snap.new); clippy clean; test-engine 18620 run with the sole failure a pre-existing foreign integration-registration guard; data/card-data.json byte-identical (H0==H_after==9fdef189), with a positive control (min_x_value=77 injected into the broad lowering path) proving the card-data probe discriminates (H_ctrl==48fbb42a). --------- Co-authored-by: matthewevans <matthewevans@users.noreply.github.com>
8 tasks
nickmopen
pushed a commit
to nickmopen/phase
that referenced
this pull request
Jul 12, 2026
…hase-rs#5646) Both cards fall under misparse-backlog root-cause category phase-rs#9 (wrong player/controller scope): - Mercenaries ("Any player may activate this ability" + a one-shot "would deal damage to you" prevention shield): the shield's recipient scope was hardcoded to `Any` rather than binding to the activator (CR 602.2a: an activated ability's controller is whoever activated it). This also affected ~27 sibling cards using the same one-shot prevention shape (Circle/Rune of Protection and others), all of which previously had zero recipient restriction on their shield at runtime. Fixed by adding a "to you" recognizer to the shared damage-recipient combinator and threading it through the prevention branch instead of discarding it. - Total War ("whenever a player attacks... destroy all ... creatures that player controls..."): the destroy effect's controller filter was hardcoded to the enchantment's own controller instead of the attacking player who triggered it. Fixed by adding a new dispatch arm recognizing "a player attacks with" as introducing the existing ControllerRef::TriggeringPlayer scope for the effect body's "that player" anaphor. - Typhoon ("deals damage to each opponent equal to the number of Islands that player controls"): verified already correct end-to-end (per-opponent ScopedPlayer binding resolves correctly in the runtime fan-out); added regression tests only, no code change. Total War's separate "except for creatures the player hasn't controlled continuously since the beginning of the turn" exemption clause remains unimplemented (a distinct dropped-modifier-clause root cause, not category phase-rs#9) and is documented as a known gap at the parse site for follow-up. Claude-Session: https://claude.ai/code/session_01XbgwGxbU9NHN9kou9isp8K Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
lgray
added a commit
to lgray/phase
that referenced
this pull request
Jul 14, 2026
…oop, current board only) ROUND-4 ADVERSARIAL REVIEW broke five more claims (Appendix B now has ten). RC-2 SURVIVED -- the reviewer could not break it and confirmed the full chain. New refutations, all measured: - B0/phase-rs#6: 'Combo B is ONE activation' is FALSE. drive_offline_kilo_freed_relic (corpus.rs:1556) takes TWO ActivateAbility actions; its comment: 'Relic has two mana abilities; the tap-self one would not fire Kilo's trigger.' The CR 605.3a nesting story is rules-legal but engine-false -- a mana ability in a ManaPayment window is still its own GameAction (engine.rs:4867). A single-action arming latch cannot capture it. - phase-rs#7: 'generalizing normalize_recast_frame lifts all 13 ObjectReentry rows' is FALSE -- it lifts ZERO. 6 rows are blocked by R6/RC-1/RC-3, not id churn; the other 7 need id-CANONICALIZATION, because stripping the churned object does not fix STABLE objects whose paired_with/attached_to point at the dead id (Deadeye Navigator never moves and still fails equality). Demoted from 'Phase 2.5 quick win' to P6, its own PR with its own soundness proof. - phase-rs#8: 'C3 is the arm no review broke' is FALSE -- ability_scan.rs:2454 sets sibling:true for ANY typed filter, so the predicate rejects Intruder Alarm, which is CR 732.2a's OWN worked example. - phase-rs#9: RC-1's 'measured trips, in order' is the wrong provenance -- board_covers runs first and returns false before the firewall is ever reached. - phase-rs#10: the Hum of the Radix fixture is UNSATISFIABLE ('each ARTIFACT spell'; Sprout Swarm is a green instant). The card is Damping Sphere. - 6 of 15 verification rows were VACUOUS, dominated by the ARMING gate. Arming (P1) is therefore a PREREQUISITE, not the last phase. Re-sequenced. - The 'Cryptolith Rite vs Earthcraft' crux pair was vacuous: Cryptolith + Squirrel Nest is NOT A LOOP AT ALL, so it declined for the wrong reason. Redesigned to hold the loop fixed and vary only the cost shape. - Corpus partition has THREE terminals (L-OFFER / L-AUTOWIN / WAIVED), and the bi-implication must fix the offline/live asymmetry UPWARD or it will pressure us into making the only game-ending path LESS sound. THE GOVERNING CONSTRAINT (user steer, now S4.6 and the spine of the plan): the player proposes a FIXED loop impactable only by the CURRENT board -- and we DRIVE that sequence on a clone. So every board ability that fires ALREADY LANDS IN DELTA. The firewall's only legitimate job is what the drive is structurally blind to: (1) monotone depletion outside the drive window -> C2 (2) a DISCONTINUITY (a threshold tripping later) -> C3 Everything else is measured: an effect that SCALES moves delta (C1); an effect that merely READS the growing axis yields constant delta and is HARMLESS -- which is exactly why today's predicate rejects the rulebook's own example. => C3 collapses from a REWRITE into a DELETION. The condition scan already exists at gate (4) (resource.rs:1524, inspects def.condition); the defect is gate (1) scanning EFFECTS. Delete gate (1), R3, R5, R6; narrow gate (4) to a Comparator against the growing axis. Deleting R6 alone is worth 2 corpus rows (Kiki-Jiki, Splinter Twin). New surface is now honestly TWO subsystems (P1 driver, P2 CR 113.6 predicate) + C2 -- not three. Assisted-by: ClaudeCode:claude-opus-4.8
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated update of README coverage badges from latest card data.