Tags

Tags give the ability to mark specific points in history as being important
  • v0.23.0

    Release: v0.23.0
    v0.23.0
    
    Commits since v0.22.0:
    - fix: two CR citations this branch wrote, and the one it copied
    - chore(release): 0.23.0 — LTR 244/244
    - docs(dev): run builds in the foreground, redirected
    - refactor(engine): ManaEmptyingStatic drops `face` too, and refuses a DFC at comptime
    - refactor(engine): drop the unexercised condition arm from ManaEmptyingStatic
    - test: pin the any_one slot guard in emptyExcept, and record the equivalent mutant on Fangorn's trigger condition
    - feat: Fangorn, Tree Shepherd
    - feat(engine): colour-scoped exemption from the CR 500.5 mana emptying
    - docs(plan): Q8 answered and closed, Fangorn unblocked, wave 39 findings
    - docs: plotting is a special action under CR 702.170b, not 702.170a
    - docs: analogue -> analog, the owner's call
    - chore: sync plan checkboxes after merge
    - test: a legendary permanent phasing in is not entering the battlefield
    - docs: second-pass American spellings — -ise/-isation family, and grey in app
    - refactor(tools): American spellings in tools, sim/tools, tests and one deck note
    - fix: payPlotCost pays without a spend-attribution sink
    - feat(app): American spellings in app strings, comments and CSS notes
    - docs(plan): American spellings in the plan files and FINDINGS
    - docs: American spellings across the prose docs and CI comments
    - chore: rebase onto next — the phasing arm, and the coverage table
    - fix: cite Sacrifice as CR 701.21, not 701.17
    - docs: record the each_opponent seat restriction as unobservable at two seats
    - test: the combat-damage-to-player record is keyed on which player
    - feat: Tom Bombadil
    - refactor: a gated probe's rollback is one operation, not two
    - refactor: payment scratch leaves cloned game state
    - feat: one mana pool per player (CR 106.4)
    - feat: Gollum, Scheming Guide
    - feat: Witch-king of Angmar
    - feat: Gandalf the White
    - docs(plan): wave-39 merge pass — two overrules, seven landed steps, 13 findings
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - docs(sim): record that settleResolutionCastOfSpell's window guard is defensive
    - fix: a resolution-cast charges its life rider once, not twice
    - test: the phase-out ORDER is what the state hash uniquely carries
    - docs(sim): state the slot rule as a balance, not a direction
    - fix: status is CR 110.5, not 110.6
    - test: the rollout clone and the position hash carry phased_out
    - fix: card headers verbatim, including the phasing reminder text
    - chore: regenerate COVERAGE.md — LTR 239/244
    - test: a same-board control behind each proposal-refusal test
    - test(fixture): expectNoProposalFrom — only the log answers "was one announced"
    - fix: the phased-in battlefield append goes through zones' own funnel
    - feat: King of the Oathbreakers
    - feat: phasing (CR 702.26)
    - docs: delete the replay-break concern; correct REVIEW.md section 9 statuses
    - docs(sim): a vtable slot is cheap; the list is about merges
    - docs: the WASM smoke harness's own comment named a retired script
    - docs(review): four of section 12's six candidates have landed
    - docs(skills): cut two rules whose subject is deleted
    - docs: stop documenting commands that no longer exist
    - docs(master-plan): delete landed rows the file's own rule says to delete
    - docs(findings): collapse closed entries to their verdicts
    - docs(plan): wave 38 merged all five; two corrections that are the planner's
    - chore: regenerate the coverage table
    - chore: regenerate the card manifest
    - feat: Doc Aurlock, Grizzled Genius
    - feat: Aven Interrupter
    - feat: Kellan Joins Up
    - feat: Make Your Own Luck
    - feat: Brimstone Roundup
    - feat: Railway Brawler
    - feat: Outlaw Stitcher
    - feat: plot as an effect, and the cost primitives OTJ needs
    - test: pin the hand walk's stand-in pick
    - chore: sync plan checkboxes after merge
    - fix: a library search stops taking the card you were about to draw
    - feat: Pillage the Bog
    - docs: stop making the conductor's report an appraisal
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - fix: the copy-order frame survived at one spell left, which its own invariant rejects
    - docs: address the !840 review — six documentation defects, no behaviour change
    - docs(dev): an absence assertion needs a witness
    - docs: re-attach three doc comments this MR had detached
    - fix(sim): hexproof on a player is CR 702.11c, and the sweep focus is creature-first
    - fix: Sharkey's borrow really does have to except mana abilities
    - fix: protection from everything obeys CR 615.12
    - test: the counterspell-vs-ordinary routing is invisible to cast enumeration
    - test: pin the routing half of Display's cast, not just the slot
    - feat: Display of Power
    - feat(sim): copy every targeted spell, in an order the controller picks
    - fix: three CR citations this diff wrote, and one absolute claim
    - fix: the new prompt kind had no board heading, and one test skipped the sweep
    - test: the library-top assertion ran against a one-card library
    - test: the copy-target window offers no second name for its keep line
    - test: the may-decline test asserted on a dead permanent's tapped bit
    - feat: Gandalf the Grey
    - feat(sim): a resolution_choices step may be modal
    - feat(sim): copy a spell chosen as a target at resolution, with CR 707.10c's window
    - revert(sim): the kicked propagation onto a targeted ETB's action was dead
    - chore(sim): regenerate COVERAGE.md for the BLB gift batch
    - feat: Coiling Rebirth
    - feat: Parting Gust
    - feat: Kitnap
    - feat: Scrapshooter
    - feat: Longstalk Brawl
    - feat: Dawn's Truce
    - feat: Sazacap's Brew
    - feat: Dewdrop Cure
    - feat: Consumed by Greed
    - feat: Mind Spiral
    - feat: Wildfire Howl
    - feat: Long River's Pull
    - feat: Valley Rally
    - feat: Into the Flood Maw
    - feat: Peerless Recycling
    - feat: Wear Down
    - feat: Nocturnal Hunger
    - feat: Blooming Blast
    - feat: Crumb and Get It
    - feat(sim): finish gift (CR 702.174) and the five surfaces its cards revealed
    - feat: refuse a delayed-only trigger event declared on Card.triggers
    - fix: the mana-emptying rule is CR 500.5, not CR 500.4
    - chore: regenerate COVERAGE.md for the three LTR singletons
    - fix: an unknown `--flag` no longer blanks a card search
    - feat: The One Ring
    - feat: Sharkey, Tyrant of the Shire
    - feat: Fires of Mount Doom
    - docs: map which fixture verb answers which staged window
    - fix: derive vtable_slots from an append-only list so concurrent raises conflict
    - fix: resolveStack silently answered the choose-permanent window
    - fix: a triggered ability going on the stack can commit a crime (CR 700.13)
    - docs(plan): wave 38 sent five back and closed the FULL-drift question
    - fix: Manifold Mouse prints a choice and implemented one arm
    - docs(plan): wave 37 closed LTR's cheap tail and three findings' subjects
    - chore: sync plan checkboxes after merge
    - chore: refresh the coverage table
    - fix: copy_of_each owes grant_source_id, which the merge silently dropped
    - docs: the gates are gone, so stop naming them as live
    - fix: drop Lazav's inert resolve_on_decline
    - chore: sync plan checkboxes after merge
    - chore: refresh the coverage table
    - test: terminate Kaervek's filter test, and prove the filter behaviourally
    - feat: Oko, the Ringleader
    - chore: sync plan checkboxes after merge
    - chore: refresh the coverage table
    - chore: sync plan checkboxes after merge
    - chore: refresh the coverage table
    - chore: sync plan checkboxes after merge
    - feat: Kaervek, the Punisher
    - feat: Lazav, Familiar Stranger
    - feat: Marchesa, Dealer of Death
    - feat: Freestrider Lookout
    - feat: Gisa, the Hellraiser
    - feat: At Knifepoint
    - feat: Servant of the Stinger
    - feat: Rattleback Apothecary
    - feat: Intimidation Campaign
    - feat: Bandit's Haul
    - feat: Hardbristle Bandit
    - feat: Duelist of the Mind
    - feat: Vadmir, New Blood
    - feat: Take for a Ride
    - feat: Seize the Secrets
    - feat: Nimble Brigand
    - feat: Slickshot Vault-Buster
    - feat: Omenport Vigilante
    - test: the nonland assertion counted cast actions, and survived its mutation
    - docs(wave): a lane killed a sibling's build with a bare pkill
    - test: the routing pair was vacuous against its own mutation
    - fix(sim): apiBounce cited CR 701.11, which is Triple
    - test: the prompt driver honours a pending extra turn (CR 500.7)
    - chore(sim): regenerate COVERAGE.md for Press the Enemy
    - test: Press the Enemy values a returned {X} spell at its cast X
    - feat: Press the Enemy
    - feat(sim): a resolving effect may target a spell on the stack
    - chore: regenerate COVERAGE.md — LTR 225 → 226/244
    - feat: extra turns (CR 500.7) and Lost Isle Calling
    - test: the only_controller bound had no test, and mutation proved it
    - chore: retire sim:lock, sim:fields and sim:oracle
    - fix: sendback — cover the reflexive half, assert ward, correct six citations
    - refactor(triggers): the watcher walk is `collect`, with the bound on the funnel
    - fix: the mill reporting bound was sized by the registry, not by the type
    - test: Shelob's provenance narrowing was untested
    - chore(sim): regenerate COVERAGE.md — LTR at 229/244
    - feat: Shelob, Child of Ungoliant and Saruman of Many Colors
    - chore(sim): regenerate COVERAGE.md for this batch's two cards
    - fix(cards): the mill citation named no rule, and two headings went unnamed
    - chore: regenerate COVERAGE.md for the two LTR cards
    - feat: Sauron, the Necromancer
    - feat: Forge Anew
    - feat: Palantír of Orthanc
    - fix(sim:oracle): the becomes-the-target rule takes either reading
    - feat: Elrond, Master of Healing
    - docs: the changelog entry is a few sentences, not a wave report
    - docs(plan): LTR's tail is three units, not eleven cards
    - docs(plan): authorize BLB, close wave 36's findings, and record what a decline-by-reading costs
    - docs(plan): saddle is 702.171, mill is 701.17, and Q7 is answered BUILD
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - test: crewing a Vehicle records no saddling
    - test: pin both arms of the saddling relation on Giant Beaver
    - chore: regenerate COVERAGE.md for the OTJ saddle batch
    - feat: Archmage's Newt
    - feat: The Gitrog, Ravenous Ride
    - test: Slickshot Lockpicker's target filter was untested
    - feat: Calamity, Galloping Inferno
    - chore: regenerate COVERAGE.md for the OTJ batch
    - feat: Fortune, Loyal Steed
    - feat: Plan the Heist
    - feat: Unscrupulous Contractor
    - feat: Slickshot Lockpicker
    - feat: Rambling Possum
    - feat: Loan Shark
    - feat: Stubborn Burrowfiend
    - feat: Pitiless Carnage
    - feat: Giant Beaver
    - fix(traits,characteristics): Nowhere to Run suppresses hexproof and ward on creatures only
    - feat: Rise of the Varmints
    - feat: Gila Courser
    - feat: Seraphic Steed
    - feat: Bridled Bighorn
    - test(combat): pin CR 506.4's blocker half at the first-strike step
    - feat: Stingerback Terror
    - feat: Freestrider Commando
    - feat(engine): EnterCtx.totalManaSpent
    - fix(combat): enforce CR 506.4's blocker half
    - feat: Bounding Felidar
    - feat: Congregation Gryff
    - feat: Stagecoach Security
    - feat: Quilled Charger
    - feat: Drover Grizzly
    - feat: Sheriff of Safe Passage
    - feat: Dust Animus
    - feat: Trained Arynx
    - feat: Demonic Ruckus
    - fix(plan): stop `sim:plan sync` eating a plan file's head
    - docs(plan): rank 7 said suspend has no cards; it has 74
    - docs(plan): OTJ is authorized, and it is dealt by parity so a family lands whole
    
  • v0.22.0

    Release: v0.22.0
    v0.22.0
    
    Commits since v0.21.0:
    - docs(changelog): 0.22.0 said LTR was 119, 183 and 225 in one entry
    - docs(changelog): extend 0.22.0 with wave 35 — The Hobbit is 188/188
    - docs(plan): triage FINDINGS and re-measure MASTER-PLAN §11 after wave 35
    - docs(plan): sweep LTR's engine claims, and restore the table sync deleted
    - docs(sim): triggerEventIndex's doc still said the index was a u64
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - test: make Supper for Spiders' duration test discriminate
    - chore(sim): regenerate COVERAGE.md — HOB at 188/188
    - feat: Supper for Spiders
    - feat: Kíli the Resourceful
    - chore(sim): regenerate COVERAGE.md for the six cards this batch landed
    - feat: The Balrog, Durin's Bane
    - chore: regenerate sim/COVERAGE.md for this batch
    - chore: regenerate registry mirror and coverage table
    - fix: a token copy created tapped entered untapped
    - feat: Storm of Saruman
    - feat: Shadowfax, Lord of Horses
    - feat: Wizard's Rockets
    - feat: Gandalf, Goblins' Bane // Flameshape
    - feat: Peregrin Took
    - feat: Mordor Trebuchet
    - feat: Pippin, Guard of the Citadel
    - feat: Troll of Khazad-dûm
    - docs(traits): record that the borrow's on_battlefield flag is measurably inert
    - feat: Phial of Galadriel
    - feat: The Watcher in the Water
    - feat: The Grey Havens
    - feat: Thranduil, the Elvenking
    - test: assert the event-set ceiling's shape, not its number
    - feat(sim): widen the trigger event set past u64, and unkey per-object budgets from it
    - feat: Saradoc, Master of Buckland
    - feat: Tale of Tinúviel
    - feat: Rosie Cotton of South Lane
    - feat: The Bath Song
    - feat: You Cannot Pass!
    - feat: Mirkwood Bats
    - fix: Heartless Act destroyed creatures that had -1/-1 counters
    - docs(plan): the full FINDINGS sweep the 2026-08-24 header said was owed
    - fix(plan): `sim:plan merge` has been broken since the tooling retirement
    - docs(plan): re-read LTR's exclusions and re-measure MASTER-PLAN §11
    - docs(plan): collapse 175 closed findings to their titles
    - docs(plan): a shape line says what the card prints, not what the engine lacks
    - feat: Long List of the Ents
    - feat: Hew the Entwood
    - feat: Morgul-Knife Wound
    - chore(sim): regenerate manifest, coverage and LTR checkboxes after lane B
    - feat: Meneldor, Swift Savior
    - feat: Isildur's Fateful Strike
    - feat: Isolation at Orthanc
    - feat: Mauhúr, Uruk-hai Captain
    - feat: Lost to Legend
    - feat: Lotho, Corrupt Shirriff
    - feat: Minas Tirith Garrison
    - feat: Gwaihir the Windlord
    - docs(plan): harvest the wave-33 findings, and correct one of my own
    - chore(sim): regenerate manifest, coverage and LTR checkboxes after lane B
    - feat: Roads Go Ever, Ever On
    - chore(sim): regenerate manifest, coverage and LTR checkboxes after lane A
    - fix(docs): goad is CR 701.15, not 701.38 — 701.38 is Vote
    - feat: Glamdring
    - feat: Goldberry, River-Daughter
    - feat: Thranduil's Decree
    - feat: Gandalf, White Rider
    - feat: Glóin, Dwarf Emissary
    - docs: cut MASTER-PLAN 1762 -> 1523, and point the fixture trap at its cause
    - docs: write for grep; demote `sim:precedent`; add the `PRINTS:` convention
    - test(sim): delete a vacuous `exclude_source` test and write down why it was one
    - chore(sim): regenerate manifest, coverage and LTR checkboxes after lane A
    - chore(sim): regenerate manifest, coverage and HOB checkboxes after !812
    - fix(sim): guard the two GameState clones with a comptime field count
    - feat: Doors of Durin
    - feat: Inside Information
    - chore(sim): regenerate manifest, coverage and LTR checkboxes after lane B
    - feat: Fall of Gil-galad
    - feat: Fog on the Barrow-Downs
    - feat: Fire of Orthanc
    - feat: Fear, Fire, Foes!
    - feat(sim): the five primitives this LTR batch revealed
    - feat: Gimli, Mournful Avenger
    - feat: Gollum, Riddle Master
    - docs(plan): write the wave-31 measured skips back into LTR.md
    - feat(charter): goad is in envelope — Q6 answered by the repo owner
    - test: the general /play save/restore round trip
    - chore(sim): regenerate manifest, coverage and LTR checkboxes after lane 2
    - docs: stop reporting `replay_version`, and re-argue the round-trip pins honestly
    - chore(sim): regenerate COVERAGE.md for the five cards this batch added
    - feat: Bewitching Leechcraft
    - feat: Barrow-Blade
    - docs(sim): the damage-source invitation on PermanentDamagedEvent is answered
    - feat: East-Mark Cavalier
    - feat: Borne Upon a Wind
    - feat: Éowyn, Fearless Knight
    - chore(sim): regenerate the manifest, coverage table and plan checkboxes after !811
    - fix(sim): hash `FloatingEffect.saddled`, and make the next omission a build error
    - docs(plan): file the saddled state-hash gap and the CR 120.3c miscitation
    - chore(sim): regenerate COVERAGE.md and sync LTR checkboxes after lane 1
    - feat: The Eagles Are Coming!
    - feat: Bill the Pony
    - feat: Spiteful Banditry
    - feat: Gandalf's Sanction
    - docs(plan): classify HOB's Supper for Spiders, the last unshaped entry
    - docs(plan): lift 56 LTR exclusions that rested on the retired kernel-spec queue
    - docs: extend the 0.22.0 changelog entry through the wave-30 retirement
    - chore(sim)!: cut `sim:bench` to the WASM smoke path and rename it `sim:smoke`
    - docs: finish the MASTER-PLAN sweep — §7, §8 and §13 against the new direction
    - docs: sweep MASTER-PLAN, CHARTER, CONTRIBUTING and the wave skill for the new direction
    - chore(sim)!: retire the `paired` throughput A/B harness
    - chore(sim)!: retire the replay sweep, the golden corpus and `certifyReplay`
    - chore(sim)!: retire `sim:text` and the rules-text generation layer
    - chore(sim)!: retire `sim:symbols` and `sim:ratchet`
    - chore(plan): sync HOB checkboxes after the lane-1 merge
    - chore(sim): regenerate COVERAGE.md for the HOB lane-1 merge
    - fix(sim): CR 611.2b — `while_source_on_battlefield` never starts if the source is gone
    - docs(plan): file the mode-scoped certification gap the wave-30 sweep exposed
    - chore(sim): retire the one ReleaseFast quarantine row, and stamp the wave-30 certification
    - docs(plan): wave-30 merge harvest — findings, skip measurements, the mutation-worktree brief
    - chore: sync plan checkboxes after merge
    - chore: refresh the coverage table
    - chore: sync plan checkboxes after merge
    - feat: Old Fat Spider Can't See Me
    - docs: two comments the CR 603.3d fork falsified
    - feat: Sting, Bilbo's Sword
    - feat: Witch-king, Bringer of Ruin
    - feat: Mount Doom
    - chore(sim): regenerate COVERAGE.md for the LTR lane-2 batch
    - feat: There and Back Again
    - feat: Dwalin, Weaponmaster
    - feat: Orcish Bowmasters
    - feat: Rise of the Witch-king
    - feat: Minas Tirith
    - fix(plan): `workable` double-subtracted an entry that was done and excluded
    - docs(plan): wave-30 prep — refresh LTR/HOB, close the CR 603.3d cluster
    - docs: record the two debts from the CR 603.3d pass in §11
    - feat(sim)!: CR 603.3d — an entry ability chooses its targets on the stack
    - feat(plan): `sim:plan merge` runs the replay certification it is responsible for
    - docs: finish the kernel-spec retirement outside tools/
    - docs(dev): the two references that still told a dev to file a spec
    - docs(tools): three comments that outlived the kernel-spec queue
    - docs: the deleted `refIsSettled` is no longer a live anchor
    - chore: delete the kernel-spec machinery from tools/
    - docs: re-derive MASTER-PLAN §11 from the tree; declare the CR 603.3d gap
    - chore(sim): the hone-counter CR drop landed — Dwalin and Sting are unblocked
    - docs(dev): `bun run test` is a landing gate, not an optional extra
    - test(sim): Lobelia's refusal test runs the fixture sweep
    - fix(sim): an engine hit must not shadow sim:precedent's card answer
    - chore(sim): regenerate COVERAGE.md for the HOB wave-29 batch
    - feat: Bilbo, Thief in the Night
    - refactor(sim): delete the dead .trigger_targets branch in castTargetSlotsFor
    - chore(sim): regenerate COVERAGE.md for the two LTR cards
    - feat: Lobelia Sackville-Baggins
    - test(sim): pin the modal-entry arm of the resolution-cast pool
    - feat: Azog, Moria's Ruin
    - feat: Aragorn, Company Leader
    - fix(sim): .attacks abilities fire at CR 508.1m, not per declaration
    - docs: record the face-resolution and back-face scope changes in AGENTS.md
    - fix(sim): resolve every printed face by name — 45 faces were gated by nothing
    - feat: An Unexpected Party // At the Door
    - chore(sim): strip every block annotation from the plan files
    - fix(sim): `sim:precedent`'s false blocker was the query, not the scope
    - chore(sim): retire the kernel-spec queue, salvaging what was measured
    - docs(wave): the merge pass certifies replay breaks, never a lane
    - chore: retire the kernel-spec queue — cards carry their own primitives
    - chore(sim): regenerate COVERAGE.md for the three HOB cards
    - test: Wizard's Staff — the Wizard equip's negative half
    - feat: Wizard's Staff
    - feat: Bard, King of Dale
    - feat: Dáin Ironfoot
    - chore: sync plan checkboxes after merge
    - chore(sim): regenerate COVERAGE.md for the LTR lane-1 batch
    - feat: Last March of the Ents
    - feat(sim): greatestStat — one parameterized slot for greatest power/toughness
    - feat: Sauron, the Lidless Eye
    - feat: Mithril Coat
    - feat: The Shire
    - feat: Rivendell
    - feat: Reprieve
    - fix(plan): next was red — three plan-integrity defects from the wave-28 adoption
    - docs(plan): wave-28 merge sweep — the Ring shape line, two adopted specs, seven findings
    - chore: data 2026.8.20
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - fix(plan): sync plan checkboxes before merge runs its gates
    - chore: regenerate sim/COVERAGE.md
    - feat: Flame of Anor
    - feat: War of the Last Alliance
    - fix: Uruk-hai Berserker prints no menace
    - feat: Arwen, Mortal Queen
    - feat: Delighted Halfling
    - feat: Aragorn and Arwen, Wed
    - feat: Took Reaper
    - feat: Uruk-hai Berserker
    - chore: refresh the coverage table
    - test(triggers): pin the entry fan-out and the announcement's owner
    - docs: record the owner's standing directive on removing process and tooling
    - docs(plan): delete the wave-20 numbering block — 2,303 lines, eight waves stale
    - feat(kernel): one entry event fires every entry ability
    - fix: the lock's own scalar set missed usize, the shape it was written to fix
    - docs(plan): wave-27 sweep — HOB is kernel-only, and "N cards from a release" was false
    - chore(sim): stamp the wave-27 both-mode roundtrip re-verification
    - docs(plan): wave-27 merge sweep — HOB's workable queue was 15, and 4 of them were real
    - chore: sync plan checkboxes after merge
    - chore: regenerate sim/COVERAGE.md for the HOB batch
    - feat: Warg Tactics
    - feat: Long Lake Nuisance
    - test: split the merge-base raise check so it can be asserted
    - feat: Esgaroth Garrison
    - fix: sim:symbols was manufacturing four of its own findings
    - feat: lock descriptor flat scalars, demote the soft ceilings that never bound
    - fix(docs): validateEmblems is validateTriggerScopes, in four places
    - fix(docs): the other fifteen symbol citations that named nothing
    - feat: sim:symbols — a gate for the symbols comments cite
    - feat: Lake-town Lookout
    - fix(docs): target_override has two writers, not one
    - fix(docs): name the validator that actually exists
    - docs(plan): wave-26 sweep — the headline finding was false and this file promoted it
    - docs(plan): wave-26 merge sweep — the multi-ETB defect was guarded all along
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - test(sim): prove a staged division's provenance is hashed
    - feat: Gandalf, Spark Starter
    - feat(sim): trigger-side divided damage
    - fix(cards): cite Regenerate (701.19), not Goad (701.15), for a regeneration shield
    - feat(sim:plan,ci): run the CR-citation existence gate in merge and test:drift
    - feat(sim:review): audit the card modules' CR citations, and gate on existence
    - docs(sim): the funnel-family checklist is fifteen, and both copies say so
    - fix: terminate the two card tests that never swept their fixture
    - docs(plan): wave-25 sweep — ten green gates over two tests that never ran
    - fix(tools): a path-qualified .md is a kernel reference only under kernels/
    - docs(plan): five kernel specs for the HOB skips, and re-triage four wrong annotations
    - docs(plan): harvest the wave-25 merge pass into FINDINGS.md
    - fix(sim): tap/untap cite CR 701.26, not 701.21 — and close two stale planner claims
    - chore(plan): retire the linked-duration control spec — a card batch solved it
    - chore: sync plan checkboxes after merge
    - chore(sim): regenerate COVERAGE.md for the HOB lane
    - feat: Radagast of Rhosgobel
    - feat: The Queen of Dale
    - feat: The Mountain-king's Return
    - docs: argue Frodo's trigger-time branch rather than caveating it
    - feat: The Lonely Mountain
    - chore: regenerate COVERAGE.md after the rebase onto next
    - fix: restore Adjust's docs, correct two citations, test the never-starts ruling
    - docs: AGENTS.md carries four rules, and the hatch count re-derived over 19
    - feat: a Present-form claim so every kernel spec is falsifiable
    - chore: regenerate COVERAGE.md
    - feat: The Ring Goes South
    - feat: Sméagol, Helpful Guide
    - feat: one reveal-until funnel with whose-library, count, tapped and remainder
    - feat: Frodo, Sauron's Bane
    - feat: Scroll of Isildur
    - feat: Rangers of Ithilien
    - feat: one control-change funnel, and the duration LTR needs
    - feat: Stalwarts of Osgiliath
    - feat: Rohirrim Lancer
    - feat: The Black Breath
    - feat: Soothing of Sméagol
    - docs(plan): wave-24 sweep — the kernel queue falls for the first time
    - chore(sim): stamp the both-mode roundtrip for the LTR/HOB card wave
    - docs(plan): retire two kernel specs !788 satisfied in a better shape than they proposed
    - docs(plan): wave harvest — three filed harms were latent, and one exposure was 1 card not 3
    - test(sim): pin the storied-ordering divergence on Bifur's own arrival
    - docs(sim): two paragraphs !788's block edge and graveyard origin falsified
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - chore: refresh the coverage table
    - revert: Aragorn, Company Leader — it cannot honestly be FULL yet
    - feat: Sauron's Ransom
    - feat: Riders of the Mark
    - feat: Aragorn, Company Leader
    - feat: One Ring to Rule Them All
    - feat: Samwise the Stouthearted
    - feat: Sting, the Glinting Dagger
    - feat: Bilbo's Ring
    - feat: Andúril, Flame of the West
    - feat: Bifur, Melodic Rider
    - feat: Elven Chorus
    - feat: Aragorn, the Uniter
    - feat: Dwarven Mauler
    - feat: Bard's Company
    - feat: Wose Pathfinder
    - feat: Flowering of the White Tree
    - docs(plan): rank 0 landed same day, and rule 3 has a vacuous-pass mode
    - docs(plan): clear the 8 baselined prose blocks; rule the three spec findings
    - fix(plan): a merged batch branch is not a live lane
    - feat(plan): gate block-annotation rot and phantom kernel specs in `check`
    - docs(wave): a brief may state a property only over the set it measured
    - feat(plan): batch refuses a lane count a live unit was not dealt under
    - docs(plan): wave-23 sweep — +16 cards, and four process defects no gate caught
    - docs(plan): wave-23 merge sweep — three MRs land, and half the skip list was already specced
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - chore: regenerate COVERAGE.md for the batch
    - feat: Sauron, the Dark Lord
    - feat: Shortcut to Mushrooms
    - feat: Ringwraiths
    - feat: Slip On the Ring
    - feat: Surrounded by Orcs
    - test(sim): Elvish Mariner's attack scry feeds its own watcher
    - refactor(sim): CommittedCounts assembles in one place, and a new arm cannot compile
    - docs(sim): warn at ctx.ringTemptsYou that nothing after it may read the bearer
    - feat: Sam's Desperate Rescue
    - feat: Elvish Mariner
    - feat(sim): CountSource.triggering_event — a count committed by the trigger event
    - chore(sim): regenerate COVERAGE.md — LTR 126 → 135 / 244
    - fix: Ringsight searches after the Ring-bearer is designated
    - docs(plan): wave-23 prep — LTR adopts 21 orphans, and 41% of its block annotations were false
    - feat: Grishnákh, Brash Instigator
    - feat: Ringsight
    - feat: Now for Wrath, Now for Ruin!
    - feat: Horses of the Bruinen
    - feat: Gollum's Bite
    - feat: Gollum, Patient Plotter
    - feat: Inherited Envelope
    - feat: Faramir, Field Commander
    - feat: Mirrormere Guardian
    - docs(plan): wave-22 sweep — the first wave the merge pass rejected half of
    - fix(plan): derive the descoped-block test's rows instead of naming them
    - docs(plan): correct the equip-cost annotations where a dev can actually read them
    - docs(plan): wave-22 merge sweep — two merged, two sent back, and a false block annotation
    - chore: sync plan checkboxes after merge
    - chore: regenerate COVERAGE.md for the batch's four cards
    - feat: Éowyn, Lady of Rohan
    - feat: Legolas, Counter of Kills
    - feat: Gandalf, Friend of the Shire
    - feat: Galadriel of Lothlórien
    - fix: both dev-brief surfaces render through one `briefLine`
    - feat: Glorious Gale
    - feat: Ranger's Firebrand
    - feat: Relentless Rohirrim
    - fix: move `app.d.ts` into a tsc program
    - fix: a `sim:precedent` miss states the question it answered
    - fix: the dev brief prints a retired block, and DESCOPED does not skim as LANDED
    - docs(plan): wave-21 merge sweep — TriggerEvent hits its 64-arm ceiling
    - chore: sync plan checkboxes after merge
    - chore: sync plan checkboxes after merge
    - test(sim): Velomachus's modal free cast — the live repro the A/B found
    - refactor(sim): inline appendOptionalAdditionalCostCasts — it was an alias with a name that no longer described it
    - docs(sim): the reader's own comment says six copies, and names the four surfaces it deliberately does not claim
    - docs(sim): ENGINE.md — the announcement fan is one reader, and which surfaces route through it
    - refactor(sim): one CR 601.2 announcement reader, not six
    - test(sim): pin CR 701.54d's "complete" — the designation precedes the watcher
    - feat: Glorfindel, Dauntless Rescuer
    - chore: sync plan checkboxes after merge
    - feat(sim): the two printed Ring watcher events (CR 701.54a/d)
    - fix(test): the name census must not go red for a missing generated input
    - fix(plan): every number under a set code says what it counts
    - docs(sim): wave 20 merge pass — §11 rewritten, findings harvested, four doc paragraphs repaired
    - chore(plan): sync LTR checkboxes — 13 cards landed in wave 20
    - chore(sim): regenerate COVERAGE.md for the batch
    - test: run the state-invariant checker while the delayed ability is on the stack
    - test: pin the choosing half of the delayed-trigger funnel (CR 603.3c)
    - fix: CR 603.3 puts a delayed triggered ability on the stack, so the step's window can answer it
    - feat: Council's Deliberation
    - chore: regenerate sim/COVERAGE.md for the five cards this batch landed
    - feat: Frodo Baggins
    - feat: Arwen Undómiel
    - feat: Elrond, Lord of Rivendell
    - feat: Dúnedain Rangers
    - feat: Boromir, Warden of the Tower
    - feat: Breaking of the Fellowship
    - fix: the 608.2b filter recheck dropped the targets already committed
    - feat: Bilbo, Retired Burglar
    - test: the temp-file leak assertion measures its own TMPDIR
    - feat: Dreadful as the Storm
    - feat: Bombadil's Song
    - feat: Enraged Huorn
    - fix(tools): every gate that reads a subprocess reads it through a file
    - feat: Fiery Inscription
    - feat: Claim the Precious
    - fix(tools): plan.ts reads its subprocesses through files, not pipes
    - chore: a .mailmap, because no git identity was configured at any level
    - docs: the wave-19 sweep — MASTER-PLAN §11, FINDINGS, and the 0.22.0 entry
    - docs(plan): release the Ring's 51 blocked-by entries in LTR.md
    - docs: retire the Ring kernel spec, and give applyEmblemTriggers its doc back
    - chore: sync plan checkboxes after merge
    - refactor(combat): gate CR 509.3d's walk on an emblem that watches it
    - fix(test): the scope test read its own subprocess short, and believed it
    - test: pin what the free-hand-cast over-approximation does and does not do
    - feat(kernel): the Ring, part 5 — tier 3's end-of-combat sacrifice
    - test(roundtrip): retire the free-cast-modal-etb quarantine row
    - fix(test): the scope test outran bun's 5 s budget, and misnamed why
    - refactor: one modal-ETB/multikicker precedence across both cast leaves
    - fix: announce a modal entry ability's mode on every cast walk (CR 601.2b)
    - docs: name the tools typecheck and sim:leak's third red path
    - fix(plan): specRepresentativeName ate the interior periods in a card name
    - fix(sim:leak): a mid-sentence FUNNEL CONTAINER claim now fails the gate
    - test: pin the typecheck's scope, so the next new directory cannot escape it
    - fix: typecheck tools/ and sim/tools/, which the gate never reached
    - docs(plan): the wave-18 sweep — the break is spent at v11, and three windows were one unit
    - docs: the three windows in ENGINE.md, AGENTS.md and the changelog
    - chore: reset the replay quarantine against the reset stream
    - chore: regenerate the golden corpus and re-record the WASM turn-cycle pin
    - test: pin CR 504.2, 507.2, 511.1 and 511.2, and regenerate the v11 replay fixtures
    - feat: open the draw, beginning-of-combat and end-of-combat priority windows
    - docs(plan): the Ring spec after parts 2 and 4 — only part 5 remains
    - feat: the Ring's tiered abilities — tiers 2 and 4, and an emblem that owns its own choices
    - refactor: one emblem-ability walk, and an emblem may have more than one trigger
    - docs: the leak gate's marker owns its line, and status names held specs
    - feat: a layer-4 supertype grant, and the Ring-bearer is legendary
    - refactor(plan): a seam under the process boundary, and the git reads behind it
    - feat(plan): status says which kernel specs are held, and what holding one costs
    - fix(sim:leak): a claim owns its comment line, so a citation stops claiming
    - docs: the wave-17 merge sweep — a CR 115.1a rules bug, and the Ring spec survived on purpose
    - docs(resolve_ctx): changeTarget reaches one target of the entry's own, not one committed ref
    - test(golden): pin the fixture-deck cell that crashed, and price what it leaves open
    - docs(sim): record parts 1+3, strike the emblem's phantom registry home
    - fix(lint-imports): the pass line says how many files it read
    - fix(plan): the MR body must not promise a deletion the merge will refuse
    - feat(sim): the Ring gets a real emblem, and its tier-1 block restriction
    - fix: a creature spell's entry-ability target is not the spell's target (CR 115.1a)
    - fix(tools): a tool must not report an outcome it did not verify
    - docs(findings): sim:plan debt's runtime section cannot see PlayerGame
    - docs: the wave-16 merge sweep — the Ring kernel is 1 of 5, and CI never had a cache
    - test(actions): the two states the projection bound assertion is about
    - test(golden): a solver fixture, because five greedy games saw no solver at all
    - feat: Birthday Escape
    - feat(sim): the Ring tempts you — CR 701.54's keyword action
    - chore: sync plan checkboxes after merge
    - fix(plan): the unknown-state notice omits a count it did not track
    - ci: test:zig declares a timeout that fits every runner; coverage --check gates
    - fix(plan): merge never reports a cause it has not read
    - docs(plan): wave 15 closed complete — four landed, and §11 re-swept on the integrated tree
    - chore: sync plan checkboxes after merge
    - docs(plan): wave-15 merge — 2 landed, 2 sent back, and §11's unit 1 row deleted
    - docs(sim): re-count ENGINE.md's trigger figures, and fix a dead symbol
    - docs: the four paragraphs this change falsifies
    - test: Torch the Tower's rider reaches a token, and that is new
    - fix(sim): the proof walk holds the CR 117 seat across a trigger pick
    - chore: sim:coverage — HOB 155/188, LTR 102/244
    - test: the controller clause, in both directions
    - feat: Stone of Erech, Head of the Hunt
    - chore(sim): retire the ability-activation kernel spec, resync COVERAGE.md
    - feat: graveyard rewrites keyed on the dying creature's controller
    - feat(sim): a whenever-you-activate-an-ability trigger event
    - perf(sim): bound the projection assertion on the invocation axis
    - docs(plan): wave-15 prep — 14 specs verified live, and two §11 rows were wrong
    - chore: scenes is import, not deck work
    - fix: the documented-script gate was red on next, and a pipe hid it
    - chore: bun run scc — line counts over tracked files only
    - chore: group the 48 scripts into three tiers, and swap lint/lint-imports
    - docs(plan): --remove-source-branch is unreliable in timing, not in firing
    - gate: wave 14 re-verifies the quarantine unchanged, and the commander exclusion was false twice
    - docs: re-measure the orphan-branch backlog — 10, not 15, and where five went is not established
    - docs: name the staged_picks arithmetic instead of implying it — 7 calls, one append, one appendSlice
    - docs: the wave-14 sweep — three rows were right about the population and wrong about the defect
    - fix: next has not parsed since 1b0a3f174 — a nested double quote in a string
    - fix: escape the quotes that made replay-roundtrip.ts a parse error on next
    - refactor: delete the narrow resolution-cast drain, dead at its only call site
    - test: widen the converter chain so the deferred-tier pick is load-bearing
    - chore: claim the last two rule-5 containers, both in cast.zig
    - test: pin CR 117.5 — a queued trigger choice is not the priority answer
    - test: the two payment walks a cost-bearing mana source used to strand
    - docs: the CR 608.2b notes name which card was actually in the hole
    - fix: a trigger-side pick is not an action taken with priority (CR 117.5)
    - test: pin the two guards in the block-declaration close
    - fix: three more places the payment walk could not see the mana it was holding
    - fix: block triggers at the close of the declaration, not per blocker
    - test: cover every TargetRef arm of the recheck's slot lookup
    - fix: stage a modal .choice cast's targets — three sites, not one flag
    - docs: a wall clock under a parallel scheduler with a deadline is a max, not a sum
    - docs: rule §11 unit 2, and re-anchor the queue against f81fe9a6a
    - fix: the CR 608.2b recheck resolves the mode and ETB specs, not just the root
    - fix: the payment walk's step gate priced a mana rock's activation cost against an empty pool
    - gate: the wave-13 quarantine reset — 30 rows over 8 causes to 20 over 1
    - docs: §11 anchors that move — cite the MR and the row, not a line in a file another lane is rewriting
    - docs: the wave-13 post-merge sweep — fourteen §11 rows falsified, and one of them was a hypothesis
    - test: make the free-cast filter pin discriminate — Shock, not an X spell
    - test: pin the free-hand-cast grant's per-card filter against the per-player hint
    - fix: a resolution-cast offer may open its own CR 601.2 windows
    - fix: the staged-cast projection bound answered "it forks" to two questions that are not one
    - docs: CHARTER records the prompt path's second bound, and who the raise advice is for
    - feat: a scoped prompt buffer — the linear mana tail gets its own allowance
    - fix: an attached Aura is rechecked against CR 303.4c, not CR 601.2c
    - docs(skills): score a mutation by the test it names, not by the count
    - docs: sim:golden pins five playthroughs, and the release-facing copy said four
    - fix: a CR 707.10f copy token keeps its token identity on the way out
    - docs: the wave-13 prep sweep — 46 findings retired, and one spec had shipped
    - fix: the native block floor dropped every "whenever this creature blocks" trigger
    - gate: the leak report deduped two different leaks into one line
    - gate: claim state.zig's 6 and zones.zig's 4 single-appender containers
    - gate: rule 5's marker learns the per-seat path
    - docs: re-sweep §11 at the integration point — the first pass was three merges early
    - gate: the combined re-sweep — 30 rows, and 2 mode-scoped causes were misfiled
    - gate: record the valve-draw reset — 82 rows -> 78, both modes agreeing
    - docs: sweep §11 against the twelfth wave — six rows falsified, four by inversion
    - gate: reset the quarantine against the matcher fix — 82 rows -> 36, 15 causes -> 9
    - test: pin the class — an omitted replay boolean is false for all nine
    - fix: an absent replay boolean means false, not "don't care"
    - gate: the stack-priority-unclear cause is fixed and deleted
    - chore: sync plan checkboxes after merge
    - fix: a replayed valve draw reproduces the draw instead of erroring
    - chore: refresh the coverage table
    - docs: the buffer comments describe the tail that exists now
    - test: pin the staged mana tail, and say which guard is redundant
    - feat: stage the mana ability's cost-object pick
    - gate: reset the widened quarantine against the modal staging — 5 rows, not 24
    - docs(sim): triggers.zig claims the two containers its funnels own
    - task: the 608.2b siblings are live, and eleven containers were ten
    - fix: the attack declaration drains its trigger choices at the close, like native
    - perf: the corpus sweep runs four games at once, and the plan catches up
    - release: the next release is 0.22.0, not 0.24.0 — three headings that never shipped
    - docs: rule the 256-cap fork — a product stages, a linear tail gets an allowance
    - fix: stage a modal cast's CR 601.2c targets, closing #403 in the base walk
    - docs: file the Equipment/LoreholdAggro per-action cost, measured not estimated
    - docs: the roundtrip corpus now plays all 1681 pairings, and the modes disagree
    - feat: sim:roundtrip pairs every vault deck with every vault deck
    - docs: sweep the plan against wave 11's subtype and combat lanes
    - fix: a combat trigger answered its own pick while a taxed trigger was owed
    - fix: a creature that entered attacking during a combat priority window was lost
    - fix: the two subtype slots could not hold a second addition
    - docs: sweep the plan against wave 10's driver lane, and escalate the cap ruling
    - fix: the prompt driver's extra family was blamed on the base walk
    - docs: sweep the plan against wave 10's first three lanes
    - fix: a creature that entered attacking during the declaration triggers was unblockable
    - feat: four more GameState containers name the funnel that owns them
    - fix: an activated ability rechecked no target at resolution
    - refactor: fold tap, tapEach, untap and untapEach into one funnel
    - fix: a noncreature's lost-abilities stamp was re-read off a thinned board
    - refactor: the artifact/enchantment destroy ran its own sequence beside the funnel
    - docs: sweep the plan against the ninth wave
    - fix: the prompt driver's trigger queue reported a stranger's pick as its own
    - refactor: collapse the destroy family to one ctx verb, and give it CR 608.2h
    - fix: stamp last-known lost-abilities for a noncreature too
    - refactor: claim four more GameState containers for the leak gate's funnel rule
    - feat: carry an in-flight departure through both clones and the position hash
    - fix: card_fixture.battlefield claims a CR 613.7d entry timestamp
    - docs: sweep the plan against the eighth wave
    - fix: apiCostObjectPower reads the board before the last-known stamp
    - refactor: collapse the type-change ctx family onto one Becomes funnel
    - docs: the CR 616.1 window does not work at the callers either
    - fix: gauntlet and ladder dropped every degradation counter
    - fix: a fire-time trigger answered whichever choice was at the head of the queue
    - chore: name cast.zig's entry attach and pin the timestamp it takes
    - docs: sweep the plan against the seventh wave
    - refactor: collapse the attach family to one CR 701.3 funnel
    - fix: the CR 616.1 pick is a candidate set, and a discard no longer re-derives it
    - fix: capture last-known power for a whole departure event, not one at a time
    - fix: a no-legal-target optional trigger is removed, not prompted
    - docs: sweep the plan against the sixth wave
    - fix: a graveyard intervener dying in the same event still applies
    - feat: Frodo, Determined Hero
    - docs: name every shipped theft that reaches the CR 616.1 divergence
    - docs: the graveyard ladder had a rung the enum never had
    - fix: the grant funnel gated on creature-ness, not battlefield presence
    - feat: gate the container-scope append the slot count cannot see
    - refactor: cast.announcementRecord shares the ActionRecord copy instead of repeating it
    - fix: CR 616.1 gives the graveyard pick to the controller, not the owner
    - refactor: fold the third hand-rolled floating-effects append
    - docs: sweep the plan against the fifth wave, and correct three of my own claims
    - test: pin a graveyard intervener dying in its victim's own state-based batch
    - fix: the /play fire-time trigger record dropped 27 of its 33 fields
    - fix: state invariants rejected every open trigger-origin target window
    - refactor: fold the last two hand-rolled adjustment appends into the funnel
    - test: pin the CR 616.1 graveyard pick, and settle that the event does not migrate
    - docs: say where the engine's pay step leaves CR 601.2's
    - docs: correct four CR citations in REVIEW.md against the pinned rules
    - docs: sweep the plan against the fourth wave, and close the citation audit
    - test: exercise the choose_permanent_picks invariant arm with the window open
    - perf: the staged cast's projection walk stops when it has every line it can offer
    - refactor: collapse the adjustment family, which had been protecting only creatures
    - feat: the multi-pick resolution choice stages, so Miasma Demon stops filling the buffer
    - feat: the damage event reaches a permanent recipient
    - fix: a trigger choice's log record dropped the scry it committed
    - docs: the any-number envelope gets its CHARTER entry
    - fix: a plural CR heading is satisfied by its singular
    - feat: audit the prose docs' CR citations under their own scope
    - fix: five CR citations in engine comments named the wrong rule
    - docs: sweep the plan against the third wave, and retract my own false finding
    - fix: the staged trigger announcement dropped eleven of its own dimensions
    - fix: eleven CR citations named the wrong rule
    - fix: the proof pass's level allocation no longer exits uncounted
    - fix: a copy effect leaves the replacement-presence memo describing the wrong card
    - fix: the any-number envelope was a numeric coincidence, not a declaration
    - refactor: applyCopiedSpellTriggers collects its batch before firing it
    - refactor: make the trigger funnel's dispatch comptime so its hand-list checks itself
    - sim: pin the .life_gained condition channel, the reason the event exists
    - sim: fold the two life-gain flags into a .life_gained replacement event
    - docs: sweep the plan against the legend-rule wave, and fold it into 0.24.0
    - feat: the legend rule declares one policy and runs two, so make it a choice
    - feat: #403's last four cast-side products stage
    - test(sim): pin what the priority window does when it reaches its step bound
    - fix(sim): the event_filter allowlist was missing six of its own dispatches
    - feat(sim): the citation audit reads every comment, not only declarations
    - fix: the combat trigger's settled commit is not a replay record either
    - docs: sweep the plan against the four-lane funnel wave, and cut 0.24.0
    - chore(sim): the entersTapped base predicate outlived its last caller
    - perf: the trigger index is +9.48% on a fixed workload
    - docs(sim): a stream break is a gameplay break for any deck that shuffles
    - docs(sim): ENGINE.md said trigger firing has no funnel at the front
    - feat!: replay stream v8 — the settled trigger commit is gone
    - refactor: 31 hand-written CR 603.2d walks become one funnel call
    - refactor: fold "creatures your opponents control enter tapped" into the replacement family
    - fix: the engine's own settled trigger commit is not a replay record
    - feat: one indexed CR 603.2d walk behind triggers.collect
    - feat: plan reap --remote sweeps the unit branches left on origin
    - fix: plan merge reads a queued merge as a failure and skips what it owes
    - fix: sim:ratchet was the one honesty gate in neither CI job
    - chore(sim): delete the dead discard auto-pick and the entersTapped alias
    - docs(sim): the main phase's window is CR 505.6, not 505.1a
    - docs(sim): the honesty section was miscounting its own gates
    - docs(sim): sweep the plan against the wave that closed it
    - docs(sim): the step bound is a CR 104.4b approximation, not an envelope bound
    - docs(sim): ENGINE.md describes one priority window, and the step bound is pinned
    - docs: record that `plan reap` blames dirt for every worktree it keeps
    - docs: triage the unit-2b harvest, with the quarantine re-measured in both modes
    - docs: record that `plan merge` cannot see a scheduled merge
    - docs: triage !739's two findings, with the branch inventory re-measured
    - test(sim): pin the reveal the discard collapse removed
    - refactor(sim): the discard family is one keyword action, so it is one verb
    - docs: triage the discard-collapse, proof-corpora and enters-tapped findings
    - test: the round-trip quarantine is 9 rows over 4 live causes
    - feat: one priority window, two action sources — replay wire format 7
    - fix: an open MR is what makes `plan start` a resume
    - fix: the enters-tapped decision reads CR 614.12's counterfactual
    - docs: triage the ReleaseFast re-measure findings
    - test(sim): state the Saga cadence and its sacrifice (CR 714.3c / 714.4 / 704.5s)
    - test(sim): prove a CR 117.1b step against the priority walk, not the seat walk
    - test(sim): state five more rules in the two proof corpora
    - fix: the roundtrip quarantine is measured in both optimize modes
    - docs(sim): decide where the damage_marked sibling declares itself, and sharpen the rollout-saturation measurement
    - docs(sim): declare the saturation ceilings, and give two comment blocks their tests back
    - fix(sim): the life ceiling is the counter ceiling's twin, and was equally false
    - fix(sim): the counter ceiling is a saturation point, not a corruption claim
    - docs(sim): the determinism break was a false invariant, and the diagnosis travelled three passes unchecked
    - chore(ci): test:ts triggers on sim scope, so the job that runs bun test sees engine changes
    - docs(sim): close the ladder test-graph finding, and check what it did not change
    - fix(sim): sim:bench walks the turn CR 117 actually opens, and a test says so
    - fix(sim): root ladder.zig in the test target, and fix the four cases that fall out
    - fix(sim): the install stamp goes to stderr, not stdout
    - fix(sim): every gate that reads the manatab binary now builds it
    - docs(sim): harvest the !731 review — the fix works, its stamp does not
    - docs(sim): the resampling default is decided, and ladder's tests never ran
    - docs(sim): harvest !728/!730, and the stale-binary false red that nearly sent both back
    - fix(sim): let the floor veto the interval — a binary separated from itself
    - docs(sim): the entry-replacement verbs carry the CR 614.12 counterfactual on their surface
    - fix(sim): CR 614.12 — an entering permanent's characteristics are read as they would be on the battlefield
    - test(sim): the unpaid half of ward on a chapter, and drop the CHARTER declaration
    - fix(sim): ward fires on a targeting triggered ability (CR 702.21a)
    - docs(sim): the aura-cooped-up hash move was a repaired fixture, not a reorder
    - feat(sim): make an A/B alternate by construction, and report what it cancelled
    - test(sim): reset the round-trip quarantine — 78 rows to 31
    - fix(sim): every CR 117 priority window opens, gated by nothing
    - docs(sim): strike the proof pass's ~4% cost — the measurement was an order artifact
    - docs(sim): retire the combat-declaration story from the two docs that still told it
    - docs(sim): the bail enum's own comment names the helpers it actually has
    - feat(sim): count how each proof pass ended, not only where its nodes stopped
    - feat(sim): name every MCTS-solver bail, so the yield's residual is measured
    - docs(sim): the filter refusal is the end state, not a waypoint
    - feat(sim): render an ObjectQuery from its structure, and wire it into ward, sacrifice, tap-other and mirror mana
    - docs(sim): the merge pass repriced unit 2 and struck a census number nothing computed
    - feat: the pinned round-trip games cover every format the corpus does
    - docs(sim): a filter predicate is a Red Line, and the metric never sets the code's shape
    - refactor: one create verb for the six token slots, and a gate the next wave can't walk past
    - feat: the replay gate sweeps every vault format, not only Standard
    - docs(sim): prep pass — orphan branches triaged, four spec pointers settled
    - docs(sim): the cost-reduction spec is two cards, and says so before its body
    - docs(sim): sweep the plan after !712-!722 — seven rows falsified, one rewritten
    - fix(plan): delete the superseded local branch instead of asking glab to reset it
    - fix(plan): wait for GitLab's head to catch up, not just its merge status
    - docs(sim): narrow the StackItem hashing gap out of #1007 and file it alone
    - chore: sync plan checkboxes after merge
    - fix(sim): the tap-cost body guard needs an opponent's end step, not any end step
    - docs(sim): retract the solver half of the instant-activation finding
    - docs(sim): say why the instant-window coverage assert is wired to one caller
    - docs(sim): re-measure the roundtrip quarantine on the instant-activation arm
    - refactor(sim): drop the two TriggerKind arms TriggerRef now names
    - refactor(sim): StackItem names a triggered ability by TriggerRef
    - fix(sim): pilots activate abilities at instant speed, and a classification keeps the window honest
    - docs: the build command belongs in AGENTS.md, and three ENGINE.md sentences were false
    - docs(sim): harvest the wave — four corrections and four findings
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - fix: MonoGElves is a legal 60-card deck again
    - feat: Arcane Denial
    - docs: the counter-replacement ordering divergence is declared, not commutative
    - fix: an off-battlefield recipient is no counter-placement event
    - perf: the counter table runs off storage its caller sizes
    - feat: Vorinclex, Monstrous Raider
    - refactor: one staging table for every counter, with the LKI it opened with
    - chore: sync plan checkboxes after merge
    - feat: Liliana, Heretical Healer // Liliana, Defiant Necromancer
    - docs(sim): the library funnel's comments stop claiming CR 701.24c/d
    - docs(sim): file the instant-activation gap that sits under every measurement
    - refactor: one putOnLibrary verb for the eight library-placement slots
    - feat: Molten Psyche
    - docs: the replay twin stops asserting what the live loop no longer does
    - feat: Necropotence
    - Revert "test(ci): PLANT a text drift — Cackling Prowler's ward reads {3}, prints {2}"
    - test(ci): PLANT a text drift — Cackling Prowler's ward reads {3}, prints {2}
    - feat(sim): a mana ability's structural riders are sentences, not refusals
    - chore: refresh the coverage table
    - feat: Bolas's Citadel
    - ci: provision bun in the zig job until the image can be rebuilt
    - feat: Spelunking
    - ci: sim:text runs in CI, on a zig image that now carries bun
    - feat: Echoing Deeps
    - feat: Boseiju, Who Endures
    - test: pin the anchored error match against an echoed file
    - feat(sim): a new roundtrip failure is retried and says whether it held
    - test(sim): close the first-strike hole in CR 510.1's strictness
    - fix: the prior reads the world the search runs in, not the real position
    - feat: Otawara, Soaring City
    - feat: the evaluator seam, before the ML phases need it
    - fix(sim): the replay fixtures carry the wire format the engine reads
    - fix(sim): a failed round-trip keeps its replay and says what the binary saw
    - feat: gate untested .full cards, and sync plan files after a merge
    - test(sim): grow both proof corpora — five CR scenarios, two mate positions
    - fix: the dies-this-turn exile rider competes under CR 616.1
    - docs(sim): Q8 — ObjectQuery.desc is UI-only, and the families render from structure
    - docs: the vault-format gap was counted by folder, and folders are not formats
    - fix: live priority after an activation matches the replay driver
    - docs: sweep the plan against the consolidation merge, and delete what landed
    - fix: a /play save mid-division keeps the points it was taken between
    - fix: drop the debug print a lane left in the replay division path
    - chore(sim): drop the empty rt.err a lane left in the tree
    - fix(sim): the forced division is CR 510.1c's second clause and nothing else
    - feat: sim:fields — the descriptor-doc gate, enabled at zero suppressions
    - feat: closed-set completeness, computed off the refusal ladders
    - feat: mcts_resample — a fresh world per rollout, not per search
    - docs: the six highest-traffic ctx verbs get their contracts written
    - docs: what the engine does with a card's board-wide statics
    - docs: what the engine does with a card's abilities
    - docs: what the engine derives from a printed cast mechanic
    - docs: what the engine does with a card's cast surface
    - docs: what the engine does with a card's printed characteristics
    - chore: data 2026.8.13
    - fix: regeneration is CR 701.19, and three more citations named the wrong rule
    - fix: counters divided among targets land as one simultaneous action
    - docs: Q7 is closed by its number — perfect information is worth +49 Elo
    - docs(sim): declare what CR 510.1c left behind, and pin the step it rewrote
    - docs: the cheat delta, beside the flag that produced it
    - fix: /play tells a missing deck from a loading one, and takes the filename
    - fix: a /play save mid-blocker-order keeps the picks it was taken between
    - feat: combat damage follows CR 510.1c, not a rule the CR deleted
    - docs: harvest the citation sweep, and the index defect under it
    - fix: "remove all counters from it" reaches lore counters
    - fix: the charter's cleanup-discard citation names no rule either
    - fix: route build:wasm through the zig cache wrapper
    - feat: a fixed mana yield is a multiset, so the sequence sorts too
    - refactor: split counter placement into its apply and fire halves
    - fix: a CR section reference cannot ride inside a citation run
    - fix: emblems are colorless by CR 114.3, not 114.6a
    - fix: miracle is CR 702.94a; there is no 702.94c
    - fix: summoning sickness is CR 602.5a; there is no 602.5g
    - fix: convoke is CR 702.51a; there is no 702.51e
    - fix: sacrifice is CR 701.21a, not 701.16b
    - fix: cleanup discard is CR 514.1; there is no 514.1a
    - fix: sorcery-speed timing is CR 305.1 / 307.1, not 505.5a
    - fix: countering a trigger is CR 701.6, not 701.5
    - fix: fabricate is CR 702.123, not 702.102
    - fix: the citation audit missed 704.5aa and every module-level verb
    - fix: a spell's mandatory target is CR 601.2c, not 601.5c
    - fix: transform is CR 701.27, not 701.28
    - fix: regenerate is CR 701.19, not 701.15
    - fix: magecraft is an ability word, so it has no CR rule of its own
    - fix: putting a land onto the battlefield is CR 701.18a, not 505.5b
    - fix: evoke's sacrifice is CR 702.74a; there is no 702.74b
    - fix: saddle is CR 702.171, not 702.169
    - fix: foretell is CR 702.143, not 702.144
    - fix: echo is CR 702.30, not 702.29
    - fix: sacrifice is CR 701.21, not 701.17
    - fix: skulk is CR 702.118, not 702.72
    - fix: meld is CR 701.42 and CR 712, not 702.83
    - fix: champion is CR 702.72, not 702.71
    - fix: a determinization must not redeal a card the position names
    - docs: record the second fan-out and schedule the next wave
    - ci: run sim:oracle and sim:leak beside sim:drift
    - docs: /play orders blockers, and the CR rule it revealed is gone
    - docs: the carry-over list landed, and the kernel spec is discharged
    - refactor(sim): the attachment settle has one departure path, not two
    - docs: the activation-cost family landed, and corrected its own justification
    - test: the /play write path crosses the kernel boundary in the app suite
    - docs: 0.23.0, and the gate that caught this plan lying
    - feat(sim): the CR 602.1b activation-cost family for sim:text
    - fix: /play names the decision it is asking about
    - chore: wire sim:leak into the merge queue
    - fix: drop the Aura conjunct from the entry-exile predicate
    - fix: the four-copy exemption is the basic supertype, not five names
    - test: the conformance sweep checks what it offers, and says where it went
    - feat: sim:leak — the engine-leak gate, measured before it gated
    - docs(sim): record the two structural calls the departure funnel had to make
    - docs: harvest the counters collapse and sim:review into the worklist
    - fix: /play can order blockers again
    - feat: sim:review — a card file beside the CR semantics of every verb it calls
    - fix(sim): the legend rule and meld take the departure funnel too
    - refactor(sim): one battlefield-departure funnel, and the two defects hiding in the retypes
    - feat(sim): CR 400.7a–m as one named, CR-indexed list
    - test(sim): pin the three contracts the counter funnel unified
    - refactor: collapse the 9 counters verbs into 1 vtable slot
    - feat: mcts_masked — the pilot denied its hidden information
    - docs: P4 measures closed sets, not a fraction of the pool
    - docs: close #403's cast side against the measurement, not a corpus
    - feat: replay wire format 4 — the Aura entry target stages
    - docs: record the damage funnel's four rules fixes in 0.22.0
    - docs(sim): the damage collapse, and the gate gap it exposed
    - chore(sim): drop the now-dead isAuraWithExileUntilLeaves alias in actions.zig
    - fix: the exile family cites CR 701.13, not 701.18
    - refactor: read the source facts once on the single-recipient route
    - test(sim): pin the three contracts the damage funnel unified
    - refactor: collapse the 9 damage verbs into 1 vtable slot
    - test(sim): pin the entry trigger's target index for Sheltered by Ghosts
    - docs: cut 0.22.0 for the MASTER-PLAN wave
    - docs(sim): the cast side of #403 was not closed, and say why nobody saw it
    - docs(sim): record #546's result and the /play blocker-ordering defect
    - fix: the ladder's half-percent sample size rounds up
    - perf(sim): pin Action's size exactly, and re-read the two comments it aged
    - docs(sim): sweep MASTER-PLAN for the wave's landed work and corrected counts
    - feat(sim): stage Sheltered by Ghosts' host × exile product
    - docs(sim): harvest the 2026-08-13 wave's findings
    - feat: the ladder reports how much of its rating is noise
    - test(sim): fail when a fixture deck stops having a golden playthrough
    - feat(sim): pin four golden playthroughs and the script that rewrites them
    - fix(sim): sim:text reads a back face's mana abilities
    - feat(sim): record golden playthroughs from the live loop
    - refactor: collapse the 18 exile verbs into 1 vtable slot
    - perf(sim): Action 544 B -> 292 B; the blocker order leaves the struct
    - feat(sim): sim:text generates mana abilities
    - fix: end the turn goes straight to cleanup, in all three turn drivers
    - feat(sim): sim:text generates kicker, multikicker and offspring
    
  • v0.21.0

    Release: v0.21.0
    v0.21.0
    
    Commits since v0.20.0:
    - docs(sim): harvest !704's three findings
    - docs: record the user-visible work the collapsed entry was missing
    - docs: collapse the three unreleased headings into 0.21.0
    - docs(sim): close the three findings !697 served, and file two queue defects
    - fix(plan): the merge test gate builds the wasm it reads
    - docs(sim): record why !701's seam is not a home for the pip mask
    - docs(sim): ENGINE.md carries the closed CR 704.5 set
    - docs(sim): record which half of the cast-cost probe filter is load-bearing
    - docs(sim): sweep the worklist after !692, and correct two records it left false
    - fix(sim): filter the cast-cost probe back to the line the window holds
    - docs: record W7 in the changelog and sweep MASTER-PLAN
    - perf(sim): keep the pip probe off casts that owe no dimension
    - chore(sim): retire two kernel specs whose work landed
    - feat(sim): stage the rest of the cast-cost announcement
    - fix(sim): a green Zig gate prints nothing again
    - docs(sim): retire the two default-meter reds and the offspring wait
    - feat(sim): the proof pass is opt-in as mcts_solver, not the mcts default
    - chore(sim): re-measure the roundtrip quarantine on this branch
    - test(sim): pin that an instant-speed window ends only on an empty stack
    - fix(sim): an instant-speed priority window ends only on an empty stack
    - feat(sim): count the proof lines the state-seeded-RNG guard refuses
    - docs: triage the 2026-08-12 merge pass findings
    - docs(sim): record what the solver measured in MASTER-PLAN §7 and §11
    - feat(sim): ladder --verify, the mcts_flat A/B seat, and aggregate sims/sec
    - feat(sim): MCTS-solver — AND-OR proof backup in the pilot
    - test: pin cast-mechanic at zero suppressions
    - fix: solve an object cost's pick and its mana as one payment
    - docs: the verb-family prefix has now been wrong in both directions
    - docs: the search family was 7 slots, as §5 predicted
    - docs(sim): record the closed CR 704.5 set
    - refactor: collapse the 7 search verbs into 1 vtable slot
    - docs: record W5 in the changelog and sweep MASTER-PLAN
    - chore: refresh the coverage table
    - perf(sim): reject the CR 704.5g arm on marked damage before any characteristic
    - docs: the graveyard-return family was 13 slots, not nine
    - fix(sim): keep the text verb's dash check out of the flag inventory
    - feat(sim): a StateBasedAction enum, one arm per CR 704.5 letter
    - test(sim): give the native-vs-WASM conformance matrix an X spell
    - refactor: collapse the 13 graveyard-return verbs into 1 vtable slot
    - docs: record the rules-text gate in MASTER-PLAN and AGENTS
    - docs: the gate list names the wrapper, not bare zig build
    - test(sim): the rules-text normalizer's own transform tests
    - fix: the repo-deck MCTS test runs every time
    - fix: a green Zig gate prints nothing
    - fix(sim): drain the whole CR 601.2 announcement in the live drivers
    - feat(sim): descriptor-generated rules text, diffed against pinned oracle
    - feat(sim): two proof corpora — CR-indexed scenarios and mate-in-N
    - feat(sim): bump the replay wire format to version 2
    - docs: the combat damage windows are closed, and the quarantine says so
    - test: the hostile-input refusals name the guard that must answer
    - test(sim): re-measure what X shares a 601.2b announcement with
    - feat: the regular combat damage step opens its CR 510.3 priority window
    - test(sim): drive the CR 601.2b window from the card fixture
    - feat(sim): stage the CR 601.2b X announcement
    - fix(sim): name the 601.2b keyword a cast label claims
    - test: apply_choice hostile-input audit (MASTER-PLAN §8)
    - fix: the staged-choice depth bound is loud, not a rules answer
    - docs: the ctx verb audit's subject axis is exhausted
    - feat(sim): give Offspring its own cast mechanic
    - refactor: collapse searchLibraryToBattlefield/…For into 1 vtable slot
    - refactor: collapse gainLife/gainLifeFor and loseLife/loseLifeFor into 2 vtable slots
    - docs: answer every open decision in MASTER-PLAN §12
    - feat: land .permanent_entered's representative and close its kernel spec
    - fix: unbreak the branch and clean up what the permanent_entered work left
    - docs: update MASTER-PLAN vtable count to 300 (was 261)
    - refactor: collapse createToken/createTokenFor and createTappedToken/createTappedTokenFor into 2 vtable slots
    - refactor: collapse draw/drawFor into 1 vtable slot
    - refactor: collapse chooseAtResolution/chooseAtResolutionFor into 1 vtable slot
    - feat: add .permanent_entered trigger event
    - docs: update stale kernel specs — exile-link and damage defects both landed
    - chore: remove the writing skill
    - docs: sweep !685 W4 target walk onto MASTER-PLAN
    - fix: sync Drakuseth FULL manifest + retarget wasm cost labels
    - docs: stop handoff — !685 W4 CI red, next tip 89f4a044
    - feat(sim): stage CR 601.2c cast target walk
    - docs: sweep !686/!687 from MASTER-PLAN and FINDINGS
    - fix: gate ObjectInMultipleZones dump off WASM
    - diag: name object + zones on ObjectInMultipleZones
    - test: pin CR 509.1h block_state after all blockers leave
    - docs: sweep MASTER-PLAN after !681–684
    - docs: mark legend-rule token cull landed in FINDINGS
    - docs: drop legend-rule token cull from known-red
    - feat: Debug event/view coherence invariant
    - feat: stage single-pick additional costs instead of fanning them
    - fix: fan as-enters choices on every cast leaf
    - fix: legend rule culls every token, not only copies
    - docs: sweep MASTER-PLAN after !675–680
    - feat: view JSON bytes per prompt kind in bench --json
    - fix: stamp Object.blocking on every block declaration
    - perf: presence-gate resetPermanentForZoneChange bump
    - feat: one checkProposedCast gate for CR 601.2e
    - feat: stack must be empty at phase boundaries
    - refactor: classify every StagedChoice family in one meta table (#361)
    - docs: sweep MASTER-PLAN and FINDINGS against 16446f9a
    - docs: make the plan safe to hand to someone who was not here
    - docs: sweep after the first-strike step, and file the half it left
    - test: quarantine the one 818-upkeep case the first-strike window widened
    - docs: sweep the plan after ward and the oracle gate
    - feat: the first-strike damage step is a real step
    - docs: say what the greedy pilot does at a ward window
    - docs: name the oracle shape gate where the drift gate is named
    - fix: Shadowmage Infiltrator declares fear
    - feat: sim:oracle, the oracle-driven shape gate
    - refactor: one card-source parser and one printed-record lookup
    - docs: retract my own perf finding, and file the two real ones
    - feat: ward uses the stack
    - docs: sweep the plan, tenth unit landed
    - fix: seed the chi-square shuffle test, and correct the null it claims
    - refactor: route the activated 608.2b recheck through the named helper
    - docs: sweep the plan against the tree, and make sweeping the rule
    - docs: spec the ward-uses-the-stack kernel
    - fix: the zig CI cache stops growing without bound
    - fix: every ability a card prints for one event fires (CR 603.1b)
    - fix: name the optimize mode `build`, as bench and ladder already do
    - fix: the roundtrip gate states the build it measured
    - feat: name the CR 613 layer set in code
    - fix: excess damage counts deathtouch, in one place
    - docs: the roundtrip gate answers differently in Debug and Release
    - docs: my own entry was one of the things the restore falsified
    - fix: every leave-battlefield funnel detaches what was attached
    - feat: restore the worklist bodies the issue migration cut
    - docs: a third of the worklist was truncated on import, and it is recoverable
    - docs: record the measured fixpoint high-water marks
    - docs: trigger firing has a funnel at the back and none at the front
    - task: whole-EventKind boundary test + known-fail test convention
    - docs: a crash on three shipped cards, filed where someone will find it
    - fix: a fixpoint that does not converge fails loudly
    - docs: the plan's three worst rows, corrected against the tree
    - fix: a staged cast announces exactly once
    - docs: excess damage takes the greatest per-type amount, not the least
    - docs: land the engine architecture program as a map
    - docs: the roundtrip gate is fine, and the trap is how it was measured
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - feat: Goblin Plate Mail — an inline amass continuation
    - feat: Goblin Plate Mail
    - feat: Mirror of Galadriel
    - feat: Silvan Reveler
    - feat: cost reduction for activated abilities, equip included
    - chore: refresh the coverage table
    - feat: Great Gilded Boat
    - feat: Sound the Trumpets
    - feat: Patient Instructor
    - chore: refresh the coverage table
    - revert: Iron Hills Stalwart stays .partial
    - fix: replay a staged cast, and re-pin the quarantine it moved
    - test: pin the ascending floor and the completion probe by mutation
    - test: pin the any-number envelope against the proposal gate
    - fix: answer a staged window from every pilot, and probe the held line
    - test: drive the CR 601.2c window, and pin the offered set by size
    - feat: propose cast targets one slot at a time (CR 601.2c)
    - feat: Glamdring, Foe-hammer // Gleam of Death
    - feat: Thorin, Mountain-king
    - feat: Stir Up Trouble
    - feat: Iron Hills Stalwart
    - feat: Ragged Short Spear
    - feat: Thorin's Last Stand
    - feat: Velvetwing Butterflies // Gaze in Wonder
    - chore: refresh the coverage table
    - docs: blocked-by is not exhaustive, and the ranking is corrected for it
    - feat: Radagast the Brown
    - docs: avgSnapshotBytes cannot see a fixed-width field, and I quoted it anyway
    - feat: Voracious Fell Beast
    - feat: Tidings of War
    - feat: Treason of Isengard
    - feat: Uneasy Partings
    - feat: The Torment of Gollum
    - chore: refresh the coverage table
    - chore: land a-whenever-you-scry-trigger-event-carryi, delete its spec
    - test: CopyException's gates use the tree's one probe generator
    - feat: Warbeast of Gorgoroth
    - refactor: drop the orphaned printed-type "still legal" recheck
    - feat: Snowslope Hunter
    - fix: a token dies with the types it has, not the ones it was printed with
    - feat: a .scried trigger event carrying the cards looked at
    - refactor: one CopyException for every copy surface
    - feat: Wargling
    - feat: Théoden, King of Rohan
    - feat: Smaug, the Great Calamity
    - docs: harvest MR A's design from a handback with no code
    - feat: Uglúk of the White Hand
    - fix: free twelve HOB cards, and make the plan buckets partition
    - docs: the ladder crash was never the kicker fan-out
    - test: Shire Shirriff's enumeration test terminates on its own open window
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - docs: COVERAGE.md leads with the notice, the total, and the table
    - style: zig fmt
    - refactor: one SeatCursor for the APNAP seat walk, and two false docs closed
    - refactor: each-player sacrifice rides StagedChoice, not a queue of its own
    - test: pin the no-window branch on the action log, not the queue
    - test: pin the no-window branch and the 256-line degradation
    - test: pin the each-player sacrifice window
    - feat: each player sacrifices creatures of their own choice
    - chore: refresh the coverage table
    - feat: Troop of Ponies
    - feat: Vow to Erebor
    - feat: Stony-Voiced Goblins
    - docs: a prohibition sits seven lines above the helper it forbids
    - test: Vow to Erebor's illegal-target test ends with the sweep
    - refactor: the six permanent types become an enum CR 110.4 closes
    - test: argue expectNoTriggerChoiceFrom by mutation in both directions
    - feat: fixture verbs for the two claims the harness could not make
    - test: gate that every card test ends with the fixture sweep
    - feat: Fixture.done asserts no choice window is left open
    - chore: refresh the coverage table
    - feat: Troop of Ponies
    - feat: Vow to Erebor
    - feat: Stony-Voiced Goblins
    - docs: drop the two kernel specs this batch landed
    - chore: refresh the coverage table
    - feat: Along the Crooked Way
    - feat: one activation can owe both a staged cost and a target's ward tax
    - test: Gundabad Opportunist names why its no-action probe filters on kind
    - chore: refresh the coverage table
    - feat: Uncover the Moon-Letters
    - feat: Desert Were-Worm
    - feat: The Balrog, Flame of Udûn
    - feat: Mirkwood Meditator
    - feat: Moment of Glory
    - feat: Shire Shirriff
    - feat: CR 601.2 proposals nest, so PendingChoiceConflict stops being a rules answer
    - test: isolate Stew the Coneys' first target slot
    - feat: Reverent Howl
    - feat: Lake-town Toymaker
    - feat: The Battle of Bywater
    - feat: Quarrel
    - test: Stew the Coneys pins both target slots, not one
    - feat: Troop of Ponies
    - feat: Stew the Coneys
    - feat: Strider, Ranger of the North
    - feat: Saruman the White
    - feat: Gundabad Opportunist
    - feat: Giant's Boulder
    - feat: Vow to Erebor
    - feat: Rising of the Day
    - feat: Old Thrush
    - feat: The Mouth of Sauron
    - feat: Warg Rider
    - feat: Guardian of the Halls
    - feat: Long-Bodied Grey Dog
    - feat: Shelob's Ambush
    - feat: Swarming of Moria
    - feat: Second Breakfast
    - feat: Elvenking's Harper
    - feat: Snarling Warg
    - feat: Goblin-town Flunkies
    - feat: Stony-Voiced Goblins
    - feat: Quarrel's End
    - docs: one of two fixes to one function is pinned, the other is not
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - docs: the import lint tells you to run a script that does not exist
    - chore: sort the flag-gate test's imports
    - docs: census against the merged tree, and LTR's shape lines are not trustworthy
    - chore: refresh the coverage table
    - feat: Quickbeam, Upstart Ent
    - fix: Shagrat's attach obeys CR 301.5b/c and cites the right rules
    - feat: Shagrat, Loot Bearer
    - docs: reconcile the completion census, escalate 403, and name the real card
    - docs: the --help claim was false, and 0.16.1 records the fix
    - fix: sim:roundtrip reads the --seeds form its usage prints
    - test: a flag value that names a real deck is still not a deck
    - fix: --help reaches the help, and --seed=7 reaches the binary
    - fix: the usage names every verb and every flag
    - feat: Samwise Gamgee
    - feat: Fall of Cair Andros
    - docs: the sweep and the probe are two commands, and only one is a gate
    - fix: a flag value is not a deck name
    - fix: sim:roundtrip names its corpus, and its 36 red seeds name their causes
    - docs: the play wrapper eats a flag's value, and --help never worked
    - feat: Saruman's Trickery
    - feat: March from the Black Gate
    - feat: Dreaded Bat-Cloud
    - feat: Boughside Wanderers
    - feat: Bofur, Reliable Guardian // Concerted Care
    - feat: Woodland Weavemaster
    - feat: Wilderland Scrounger
    - feat: Troll Negotiations
    - feat: Thrór's Map
    - feat: Shire Terrace
    - test: the prompt path is pinned to refresh before a choice dispatch
    - feat: Oath of the Grey Host
    - feat: Merry, Esquire of Rohan
    - feat: Shire Scarecrow
    - docs: bun install is the fresh-worktree remedy, not svelte-kit sync
    - feat: Tom, Bert, and William
    - feat: Pippin's Bravery
    - feat: Rush the Room
    - fix: unit start bootstraps the worktree, and names what it did not do
    - feat: Mines of Moria
    - feat: Pinecone Strike
    - fix: Shower of Arrows carries the pilot removal hint
    - test: prove the shared activation prologue runs on all six arms
    - fix: the prompt path refreshes hand-free-cast like the other three
    - feat: Mirkwood Channeler
    - feat: Iron Hills Stalwart
    - feat: Revive the Shire
    - feat: Through the Forest Gate
    - test: pin the synthesize-cast declaration and its membership gate
    - chore: a raised ceiling keeps its rule, and three stale copies catch up
    - chore: raise the TriggeredSpec and StaticSpec ceilings
    - feat: Ioreth of the Healing House
    - feat: Rally at the Hornburg
    - refactor: name the activation proposal, and fix the arm that drifted
    - test: the membership gate is load-bearing at three cast-side families
    - feat: Lembas
    - feat: Thranduil's Company
    - feat: Magnificent End
    - refactor: one membership gate for the proposed action
    - feat: Mushroom Watchdogs
    - feat: Enchanted River's Grasp
    - feat: Shower of Arrows
    - feat: Oin the Brave
    - docs: name the leftover-worktree refusal in CONTRIBUTING
    - feat: Dwarven Shortsword
    - feat: Prince Imrahil the Fair
    - feat: Dwarven Provisioner
    - feat: Bolg's Company
    - feat: Attercop
    - feat: Lakeshore Apothecary
    - fix: plan refuses a unit worktree path git does not own
    - feat: detect one primitive claimed by two MRs
    - fix: the worktree registry decides what a worktree is, not existsSync
    - feat: Great Fierce Bee
    - feat: Mordor Muster
    - chore: a raised ceiling keeps its rule, and three stale copies catch up
    - refactor: one offer dispatcher, not four copies of it
    - feat: Ravening Warg
    - feat: Smaug's Fury
    - chore: raise the TriggeredSpec and StaticSpec ceilings
    - docs: harvest the wave boundary, and retract two plan-file claims
    - test: Haradrim Spearmaster reaches the new default through beginCombat
    - fix: one ResolveCtx.isLegendary, not two
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - chore: refresh the coverage table
    - feat: close the runCombat and planeswalker-loyalty doors on the same shape
    - feat: Faramir, Prince of Ithilien
    - feat: Grond, the Gatebreaker
    - feat: Gorbag of Minas Morgul
    - feat: Friendly Rivalry
    - feat: Horn of the Mark
    - feat: Grima Wormtongue
    - feat: Great Hall of the Citadel
    - feat: Galadhrim Bow
    - feat: Hobbit's Sting
    - feat: Haradrim Spearmaster
    - feat: Gimli's Fury
    - feat: The Great Goblin
    - feat: Old Man Willow
    - feat: Nimble Hobbit
    - feat: Legolas, Master Archer
    - feat: Orcish Medicine
    - feat: Moria Marauder
    - feat: Horn of Gondor
    - feat: Nasty End
    - feat: Lash of the Balrog
    - feat: Meriadoc Brandybuck
    - feat: Mirkwood Spider
    - feat: Protector of Gondor
    - docs: correct the fixture prose the new default falsifies
    - test: tripwires for the two harness defaults this unit changed
    - test: name the choice at 60-odd call sites the harness was answering
    - feat: the fixture holds at every queued trigger choice that is a fork
    - feat: Orcrist, Goblin-cleaver
    - feat: The Arkenstone // Seek the Heart
    - feat: Thranduil, Sindarin Liege // Silvan Rally
    - feat: Dáin, Lord of the Iron Hills
    - feat: Bombur, Gentle Dreamer
    - feat: The Lord of the Eagles
    - feat: The Sackville-Bagginses
    - feat: Well-Worn Spatula
    - feat: Wood Elves
    - feat: Bilbo's Deadly Slice
    - feat: The Notary Hobbits
    - feat: Getaway Barrel
    - feat: Part in Friendship
    - feat: Stone-Giant of High Pass
    - feat: The Misty Mountains Cold
    - docs: harvest the task-MR pass, and correct the buffer ceiling to nine
    - feat: Thorin Oakenshield
    - feat: Roll-Roll-Roll-Roll
    - feat: The Black Arrow
    - feat: Smaug the Magnificent
    - feat: The Master of Lake-town
    - feat: The Chief Warg
    - docs: harvest six findings from the HOB/LTR merge pass
    - docs: the land-play special action is CR 116.2a, not 505.5b
    - chore: refresh the coverage table
    - refactor: derive commitsEntryChoices from wasCast
    - chore: refresh the coverage table
    - fix: an entry trigger keeps its targets on a non-cast entry
    - chore: refresh the coverage table
    - fix: one payment reader for every cast-enumeration gate
    - chore: refresh the coverage table
    - docs: REVIEW.md step 1 has landed, and the file now says so
    - fix: plan start refuses a specless kernel, and status names dangling refs
    - fix: drop the worktree's zig cache, not the main clone's
    - docs: plan drops the main clone's zig cache, never the worktree's
    - ci: expire job artifacts
    - chore: refresh the coverage table
    - docs: StaticSpec is over ceiling, and Kili gets a real blocked-by
    - feat: raise the coverage floor to ten covered cards
    - feat: Smaug, Wicked Worm
    - docs: mark LTR's 32 phantom entries, and retract a bad detector
    - feat: a covered-card floor under the coverage table's ratio rule
    - feat: Bilbo, Luckwearer // Burglar's Plot
    - feat: a generated per-set coverage table
    - docs: Q5 answered — widen the permanent_damaged dispatch
    - feat: My Precious // Allure of Power
    - feat: Bolg of the North
    - feat: Beorn's Hospitality
    - docs: a Q5 for the human, and the fixture auto-pick is now four verbs
    - feat: Foray of Orcs
    - docs: the two meters disagreeing is the phantom-entry detector
    - feat: Gollum, Silent Slinker // Meager Meal
    - feat: Elven Farsight
    - feat: Elanor Gardner
    - feat: Settle the Wreckage
    - feat: Bill Ferny, Bree Swindler
    - feat: Éomer, Marshal of Rohan
    - docs: Bilbo was never unblocked, and cast provenance has no command zone
    - feat: Rhovanion Rampager
    - feat: Beorn the Fierce
    - feat: Galadriel, Gift-Giver
    - feat: Lake-town Mariners // Gone Fishing
    - feat: Barad-dûr
    - feat: Stone by Sunlight
    - feat: Balin, Loremaster
    - feat: Assault on Osgiliath
    - feat: Book of Mazarbul
    - feat: Most Decrepit Old Bird // Speak Secrets
    - feat: Gimli's Axe
    - feat: Erkenbrand, Lord of Westfold
    - feat: Plunder the Trollshaws
    - feat: Rage into the Valley
    - feat: Gimli, Counter of Kills
    - feat: Confusticate and Bebother
    - feat: Fíli the Pathfinder
    - feat: Generous Ent
    - feat: Escape from Orthanc
    - feat: Gothmog, Morgul Lieutenant
    - feat: Deceive the Messenger
    - feat: Nori, Teller of Tales
    - feat: Easterling Vanguard
    - feat: Old Fat Spider
    - feat: Dunland Crebain
    - feat: Ravenhill Flock
    - feat: Nasty Little Rabbit
    - feat: Ordinary Bear
    - feat: Nighthowl Pursuer
    - docs: classify the 49 new HOB entries
    - docs: record the meter's set-attribution drift across a data pin
    - chore: HOB adopts the 49 cards the 2026.8.7 data pin added
    
  • v0.20.0

    Release: v0.20.0
    v0.20.0
    
    Commits since v0.17.0:
    - feat: the social card is Manatab's, and comes from the same drawing
    - docs: 0.20.0 is the new-icon release
    - fix: even out the caption rows, and let the chips fill their line
    - fix: the hero credit named itself twice, in two overlapping ways
    - feat: the format chip abbreviates, and carries the precon's set
    - feat: deck tiles wear the deck page's stat chips (#829)
    - feat: new site icon, redrawn from one SVG
  • v0.17.0

    Release: v0.17.0
    v0.17.0
    
    Commits since v0.16.0:
    - docs: 0.17.0 is the set-links release
    - fix: ask_user was marked quiet, which told the model never to ask
    - feat: Tutor can ask a question and wait for the answer
    - feat: set codes link everywhere, and carry a popover of the set
    - fix: the hero scorer's word boundaries were backspace bytes
    - chore: open the UX improvements branch
  • v0.16.0

    Release: v0.16.0
    v0.16.0
    
    Commits since v0.15.1:
    - docs: 0.16.0 states The Mindskinner's kernel once
    - docs: 0.16.0 is the Duskmourn release
    - docs: DSK closes at 266/266; harvest the merge-pass findings
    - chore: DSK plan file records Tamiyo and Valgavoth as landed
    - docs: harvest the DSK merge-pass findings
    - chore: data 2026.8.7
    - fix: a scheduled data run is never redundant, so stop cancelling it
    - docs: settle where damage_cant_be_prevented lands, and retire the spec
    - fix: the weekly data refresh could never have run
    - test: hexproof holds off the opponent, and damage marks instead of loyalty
    - test: stock your own library so the each-opponent scope can actually fail
    - docs: the weekly data refresh had no schedule and nothing checks that
    - test: the WASM prompt machine folds a ninjutsu attacker in too
    - docs: the clone/hash completeness gate is itself a hand-list
    - fix: keep the no-memo paragraph attached to cardTypesInGraveyard
    - test: pin "each opponent" to the replacement's controller, not the damaged seat
    - feat: a damage-to-a-player replacement that substitutes another effect
    - docs: changelog for ninjutsu and the layer-4 static type change
    - docs: two kernels land, and the merge queue reports two more false failures
    - docs: layer 4, the combat roster, and the ninjutsu constructor
    - test: a driver run pins the late-attacker fold-in
    - test: the ninjutsu activation logs CR 702.49a's reveal
    - test: real-state proof for ninjutsu, the layer-4 static, and the new state
    - feat: ninjutsu (CR 702.49) and a layer-4 static type change
    - test: drop an unused binding in Valgavoth's ward-count test
    - docs: changelog records the position-hash fix
    - feat: Valgavoth, Terror Eater
    - docs: the paragraphs this kernel falsified, and a gate for the next one
    - docs: drop blocked-by annotations naming specs that no longer exist
    - test: close the three gaps the mutation matrix found
    - fix: retarget labels read the pick where this kernel put it
    - test: mode 2 retargets a triggered ability, not only an activated one
    - fix: ward's choice-cost switches name the third target arm
    - feat: The Tale of Tamiyo
    - docs: the DSK merge pass records two rulings and four findings
    - feat: copies of exiled graveyard cards, cast during the resolution that made them
    - docs: ENGINE.md maps CR 603.2d, and the kernel spec retires
    - fix: gate each extra trigger instance separately (CR 603.3b)
    - docs: restore next after reviewing a merge request
    - test: pin the land-play, life-loss and block fire sites
    - docs: ward's mandatory payment becomes a named envelope approximation
    - test: pin saga-chapter doubling (M10 read silent)
    - test: pin the entry funnel's 603.2d payment (M8 read silent)
    - feat: Mirror Room // Fractured Realm
    - docs: the cast_spell announcement paragraph scopes itself to the ward path
    - wip: pay CR 603.2d at the remaining bare fire sites
    - test: the token play-permission pin says what it can and cannot prove
    - wip: CR 603.2d additional trigger instances + Mirror Room
    - docs: the kernel spec lands, and two docs it falsified
    - test: a replay fixture that retargets through the new action encoding
    - docs: the becomes-blocked paragraphs say what the code guarantees
    - docs: three kernels land, and six plan entries stop naming specs that are gone
    - feat: Untimely Malfunction
    - docs: the runtime target-count sources, and the kernel spec is delivered
    - fix: drop dead resolve_on_decline from Miasma Demon's discard choice
    - feat: name an activated or triggered ability on the stack
    - test: pin the firing-sized target lint arm
    - feat: a reflexive trigger's target count sized by its arming payment
    - chore: land the graveyard play/cast kernel, retiring its spec
    - docs: ward gates one DSK card, Kaito needs two primitives, and three findings land
    - test: the blanket graveyard permission outlives a card leaving the zone
    - docs: repeat-loop surface in ENGINE.md, changelog bullet, spec retired
    - docs: the paragraphs that carried the false premise now carry the true one
    - fix: drop a dead token guard from the turn-scoped graveyard replacement
    - test: pin the repeat batch through the rollout clone too
    - docs: the counter-kind checklist counts five sites, not three
    - test: Forgotten Cellar's exile replacement leaves tokens alone
    - test: pin one announcement per repeat pass, empty library included
    - feat: the choose-or-reveal cost arm records which half was paid
    - test: gate PlayerGame's scalars for clone and hash completeness
    - test: pin the repeat loop to exactly X passes
    - feat: play lands from your graveyard, and two turn-scoped graveyard permissions
    - docs: Card.delayed_triggers says which scopes the lint allows and which it refuses
    - test: pin the repeat loop's batch invariant, clone and position hash
    - feat: repeat a look-top window exactly N times, accumulating what it made
    - docs: say which callers of the activated funnel gate and which hide
    - test: the borrow segment hides dead lender abilities, and the stack survives it
    - docs: the changelog records the ward kernel and the replay-window fix
    - fix: a staged pick at instant-speed priority does not restart the window
    - docs: a change that falsifies a doc paragraph is a sendback
    - docs: the 2026-08-07 merge pass sends all three MRs back and harvests findings
    - test: the ward window announces once, replays, and survives two targets
    - test: hold the block close so a spurious becomes-blocked trigger is visible
    - fix: a ward-staged cast or activation announces itself exactly once
    - feat: becomes-blocked event and play-from-exile for a permanent
    - docs: changelog entry, and the keyword-counter spec is delivered
    - feat: deathtouch keyword counters; Qarsi Revenant renew places real counters
    - fix: the ward-cost family rejoins next's two new exhaustive ActionKind switches
    - docs: the DSK merge pass harvests its findings and corrects two stale specs
    - feat: lifelink keyword counters (CR 122.1b) and Reluctant Role Model
    - fix: a stack item's grant source is a distinguishing reference
    - test: two of your creatures dying to one sweep exile two cards
    - test: a land proves the borrow is creature-scoped
    - test: Marvin borrows a granted ability, and the name clause blocks a twin
    - feat: Marvin, Murderous Mimic
    - feat: a delayed trigger narrows by scope, and Waltz of Rage
    - fix: the merged arming funnel refuses a swapped chooser at compile time
    - docs: manifest-dread watchers reach the 0.16.0 changelog
    - docs: the 0.16.0 entry records the discard work
    - feat: fail when the committed card registry is stale
    - test: pin manifest dread's arm-site announcement and the gone-buried-card ruling
    - chore: the registry regains its Excruciator after the merge
    - docs: the face-down library exile spec lands with its representative
    - chore: release 0.16.0 — behold, gift, and gates that measure what they print
    - feat: detect when main has commits next never got
    - docs: retire 38 kernel specs no card and nothing else names
    - docs: a dev delivers what it took
    - fix: the graveyard sacrifice cost cites CR 701.21a, not Mill
    - docs: kernel specs for the four cards this batch skipped
    - feat: Last Light of Durin's Day
    - feat: quest counters
    - feat: Hobbit Hole
    - feat: Gollum the Abandoned
    - feat: a graveyard activation can pay a sacrifice cost
    - feat: Misty Mountains Raider
    - feat: Gathering of Darkness
    - fix: fx.attack fires the batched attackers-declared triggers
    - feat: Mirkwood
    - feat: Lake-town
    - feat: Elvenking's Halls
    - fix: the failed-search arm is tested, the header carries its reminder text
    - docs: the behold kernel spec is landed
    - feat: Elven Passage
    - feat: behold (CR 701.4a)
    - feat: a resolution choice can name the subject its continuation refers back to
    - fix: sim:roundtrip takes a bare deck name
    - fix: manatab validate reports only what it measured
    - fix: the gift is held on a 608.2b fizzle, and the review's citations and docs land right
    - docs: commit the spec DSK's plan file already points at
    - docs: DSK questions 1 and 2 answered — all 18, and keyword counters keep their counts
    - fix: the manifest sync gate compares every mirrored field
    - docs: the gift kernel spec is landed
    - feat: gift (CR 702.174), spell-to-hand, and a symmetric turn-scoped cast lock
    - fix: a replay fixture holds a migrated discard, and the review's minor notes clear
    - fix: printActionLog writes every replayable ActionRecord field
    - test: pin the replay fields printActionLog drops (red)
    - ci: run test:zig on merge request pipelines
    - docs: DSK phantom sweep — one spec struck, two stale claims corrected
    - fix: an empty hand ignores only the discard, and the subset walk counts combinations
    - docs: An Unexpected Party points back at the spec that gates it
    - docs: HOB questions 4 and 5 answered — Adventure back faces in, keyword-only cards untested
    - docs: a set reaching 100% coverage is a minor release
    - docs: retire the effect-driven discard kernel spec
    - feat: random discard for Hymn to Tourach; chain the each-player discards
    - feat: enumerated discard for the modal, two-card and tailed families
    - feat: enumerated discard for the opponent and effect-named families
    - feat: migrate the self-discard family to the enumerated pick
    - feat: enumerated resolution-time discard, proved on Psychic Whorl
    - docs: HOB architecture review — gate reach, choke-point verdict, hand-list correction
    - docs: the bare-action sweep closes as a measured boundary
    - docs: the two-piles kernel spec is landed
    - feat: Riddles in the Dark
    - fix: drop a stray debug print from the Goblin-town chapter
    - docs: an entry trigger loses its targets on every non-cast entry
    - docs: two human rulings land before the lanes reach the gate
    - feat: Down, Down to Goblin-town
    - docs: kernel specs for the two blocked HOB lane-2 cards
    - feat: Key to the Side-Door
    - docs: kernel spec for a reflexive trigger reading its arming cost object
    - feat: Great Ugly-Looking Goblin // Clap! Snap!
    - feat: Master's Councillors
    - docs: kernel spec for an optional target slot ahead of a mandatory one
    - feat: Mirkwood Nurturer
    - feat: Little Bear
    - feat: Gloin the Mighty // Easy Pickings
    - feat: Storied and the enduring story designation
    - feat: Iron Hills
    - feat: Large Bear
    - feat: Gandalf, Wandering Wizard
    - feat: Fearsome Goblin Pair
    - feat: Mirkwood Pathmaker
    - feat: Front Porch Sentries
    - docs: HOB wave prep — strike the amass authorization and three stale specs
    - docs: rename the architecture-review skill to arch
    - fix: manifest dread's comptime lint follows count_from_x onto count_source
    - docs: ten landed kernels release their plan entries
    - perf: a kernel MR stops paying for Playwright, and the pipeline learns its stages
    - fix: two test files leave the catalogs primed and fetch stubbed
    - docs: wave harvest — four live defects, two process findings, hone re-shaped
    - docs: sync plan checkboxes; Untimely Malfunction points at the successor spec
    - fix: the merge kept two copies of bear_2_2
    - fix: retarget_choice picks its side in the two ActionKind authorities
    - chore: the last two lines still naming the old Pages host
    - chore: regenerate manifest
    - fix: wire the ward-cost staged family into next's exhaustive switches
    - chore: regenerate manifest
    - docs: a release without a changelog entry stops being possible to miss
    - chore: regenerate manifest
    - docs: the baseline guide sheds what --help and CONTRIBUTING already carry
    - docs: the look-top power/distinct spec lands
    - feat: Rip, Spawn Hunter
    - feat: a look-top count read off the source's power, and distinct picks
    - docs: the guide stops naming caches, counts, and clobbers the tree outgrew
    - docs: fold session memories into the agent guide
    - feat: a whenever-you-manifest-dread trigger, and the card that window buried
    - chore: the unlock-cost-reduction spec leaves the queue
    - docs: the new round-trip gate cannot notice it stopped testing anything
    - docs: the kernel queue swaps a landed spec for the one Untimely Malfunction needs
    - feat: Inquisitive Glimmer
    - feat: a cost reduction says which payment it takes off
    - docs: three kernel specs for this batch's skips
    - feat: Galion, Elvenking's Butler
    - docs: kernel specs for the two cards this batch skipped
    - feat: Entish Restoration
    - feat: Ent-Draught Basin
    - feat: Eagles of the North
    - feat: Dúnedain Blade
    - feat: Denethor, Ruling Steward
    - feat: Dawn of a New Age
    - feat: Cast into the Fire
    - feat: Bitter Downfall
    - feat: Bag End Porter
    - feat: Arwen's Gift
    - fix: the activation-count invariant test asserts the rule that replaced it
    - feat: Gnashing of Teeth
    - test: assert the candidate set, not only the pick
    - feat: retainsPriority and isProposalStep, the two ActionKind authorities
    - docs: amass lands, and 36 entries stop naming a spec that is gone
    - feat: Gleaming Splendor
    - test: pin the retarget walk against its rulings and its clone identity
    - feat: a search across graveyard, hand and library, and a staged multi-pick graveyard cost on an activation
    - docs: three promotions, one of them bought by a negative result
    - feat: change the target of a spell, a legality walk over somebody else's spell
    - fix: a play-emitted replay carries all four outcome fields
    - feat: Elven Raft-Steerer
    - feat: Errand-Rider of Gondor
    - feat: Erebor Flamesmith
    - feat: Eomer of the Riddermark
    - feat: Ent's Fury
    - feat: Eastfarthing Farmer
    - feat: Eagle of Deliverance
    - feat: Cirith Ungol Patrol
    - feat: Captain of Umbar
    - feat: Butterbur, Bree Innkeeper
    - feat: Brandywine Farmer
    - feat: Banish from Edoras
    - docs: kernel spec for the token-entry watcher
    - feat: Desolation of Smaug
    - feat: Eagle's Rescue
    - feat: Beorn, Reluctant Host
    - feat: Cantankerous Keepers
    - feat: Bard the Bowman
    - feat: Dancing from Dark to Dawn
    - feat: Dori, Bearer of Friends
    - feat: Iron Hills Blacksmith
    - docs: correct the amass inline-path rationale to CR 701.47a
    - docs: the exile-link retrieval spec is spent
    - feat: Eagle of the Great Shelf
    - feat: Goblin-town
    - docs: the SBA boundary inside a resolution gets named
    - feat: an exile-link retrieval reads the rest of its printed line
    - feat: Fateful Discovery
    - docs: sim:roundtrip, and the u64 trap that costs an afternoon
    - feat: Gigantic Big Bear
    - fix: a recorded activation opens its stack-priority window on replay
    - docs: the graveyard-arrival kernel spec is spent
    - test: the mill finishes before either land returns
    - feat: Hedge Shredder
    - feat: cards put into a graveyard announce one batched arrival
    - feat: a graveyard arrival can be declined
    - docs: the card-cache blocker is closed, and the wider read is recorded
    - fix: bun install writes the tsconfig the aliases resolve through
    - feat: amass (CR 701.47) and Bothersome Noisemaker
    - docs: the last gate consumer that still learns by exception
    - docs: two kernel specs name what blocks the last two HOB lane-2 cards
    - fix: the data stamp records what it wrote, and install re-hashes it
    - docs: two pool entries get verified instead of aging
    - docs: two gates get measured instead of trusted, and a landed kernel is cleared
    - feat: Down in the Valley
    - fix: a landfall trigger's printed condition is finally asked
    - chore: the creature-sourced damage sweep leaves the kernel queue
    - test: Nova Flame pins the source's deathtouch across the sweep
    - feat: Nova Flame
    - feat: a named creature can be the source of a damage sweep
    - fix: a worktree gets its card data, and an absent cache stops reading as drift
    - feat: The Rollercrusher Ride
    - test: the X-sized trigger target gate names what it refuses
    - chore: regenerate registry manifest for Desolation of Smaug
    - feat: Burn, Burn, Tree and Fern
    - test: an over-committed target count is refused at cast time
    - docs: kernel specs for the five HOB cards this batch skipped
    - feat: Desolation of Smaug
    - feat: Chief Warg's Company
    - feat: a permanent already on the battlefield has an X of zero
    - docs: the kernel spec is spent
    - feat: Dain's Company
    - feat: Duskwatch Hunter
    - feat: Bejeweled Warg
    - feat: Crude Bent Blade
    - feat: Dwarven Mattock
    - feat: Bilbo Baggins, Burglar
    - feat: Desolation Prowler
    - docs: Found Footage stops naming a kernel that landed
    - chore: regenerate registry manifest
    - feat: Dancing from Dark to Dawn
    - feat: Cantankerous Keepers
    - feat: Beorn, Reluctant Host // Till and Tend
    - feat: Bard the Bowman
    - feat: Dori, Bearer of Friends
    - test: the declaration gate is pinned from both sides of combat
    - feat: a declaration that would leave one creature attacking alone cannot close
    - feat: a trigger's target count reads the X its permanent was cast for
    - feat: Iron Apprentice and Host of the Hereafter
    - feat: put the counters a creature had onto another creature
    - docs: LTR gets read card by card, and the merge queue learns why drift died
    - docs: the scope answers land, and two records stop citing work the tree lacks
    - feat: the grant stops at the battlefield, and the spec is spent
    - test: the zone-change reset drops the exile facing
    - docs: the required shape for a closed set with more than one reader
    - docs: HOB's other 130 entries get shapes, and nine kernels name what gates them
    - chore: retire the attacks turn-limit kernel spec
    - fix: the four game_loop staged-action lists become one closed predicate
    - feat: Fear of Missing Out
    - feat: Doomsday Excruciator
    - feat: a card exiled face down is one no player can read
    - docs: HOB and LTR get plan files, and two kernel specs name what gates them
    - feat: a per-viewer grant to look at face-down permanents
    - fix: Heartless Act can remove every kind of counter, and two switches close
    - feat: one classified list of Cost arms, and both readers walk it
    - feat: an attacks trigger claims "the first time each turn" at the event
    - docs: the plan files drop three landed blockers, and findings names the branch drift
    - feat: a turn-scoped delayed triggered ability that watches an event
    - docs: record the choice-carrying ward kernel and retire its spec
    - feat: ward costs that carry a choice, on both payment paths
    - feat: add the choose-or-reveal cost arm and Monstrous Emergence
    
  • v0.15.1

    Release: v0.15.1
    v0.15.1
    
    Commits since v0.15.0:
    - fix: two test files leave the catalogs primed and fetch stubbed
    - fix: clicking a deck opens the deck, not its hero card
  • v0.15.0

    Release: v0.15.0
    v0.15.0
    
    Commits since v0.14.1:
    - chore: declare 0.15.0, the release the morning forgot to write down
    - feat: the flask takes over the tab, and the nav learns the name
    - feat: the pane's price is a fold now, first after the rules text
    - feat: the card pane says what the card costs
    - feat: the built site gets clicked before it ships
    - chore: the flask sketches stay out of the tree
    - chore: the repo answers to manatab now, and every link says so
    - fix: the source menu stays on screen, and the phone pane stops taking its width from its children
    - feat: a card knows what it costs in money, not only in mana
    - fix: an empty Anthropic reply says why, and Stopped. means the user stopped it
    - fix: a chip that edits the deck is not offered where edits can't land
    - fix: install checks the tree, not just the stamp
    - fix: the unfurl stamp rides build:site, which is the build CI runs
    - fix: the stamp tool's imports sort — the gate couldn't see an untracked file
    - fix: og: URLs live on manatab.app now
    - fix: local deck pages render again, and vault unfurls move to a post-build stamp
    - chore: six thousand lines of narration go quiet in app/ and tools/
    - feat: the orb holds water now, and the tab floats on top of it
    - feat: the favicon is the orb, the wave, and the way out
    - fix: app.html stops narrating into the page, and the markup comments go quiet
    - fix: a legal Commander deck stops linting as one card over
    - feat: the changelog is a page, and the version number is its door
    - fix: the scene page's Back link cannot leave the site
    - fix: an old local deck gains its created: line on the next save
    - fix: the gallery says every shipped deck is read-only, not just the vault
    - feat: a shared vault deck unfurls as itself
    - fix: a Tutor thread remembers the model that wrote it, and goes read-only under another
    - chore: the reshuffle the rule was owed — 26 .svelte files sorted
    - fix: the import linter reads indented lines, so .svelte files count
  • v0.14.1

    Release: v0.14.1
    v0.14.1
    
    Commits since v0.14.0:
    - fix: a deck with one card across several printings can select each line
    - feat: a deck's face is chosen by identity, not census
    - fix: the credit's card name is actually hoverable
    - fix: the name line breathes, and the key line settles at two
    - fix: a precon opens at once, and Back keeps the tiles' stats
    - feat: every deck link opens on its hero, and card names preview on hover
    - feat: tile card names open the deck with that card pinned, and a third key
    - feat: the tile's right edge earns its keep — artist, health, key cards
    - fix: the tile's name steps up a size, and the facts share one line
    - feat: the card view folds into the art tiles as a minimized stat card
    - fix: the reveal window survives Back
    - feat: precons resolve through the vault pipeline, so every view works
    - fix: every column header in the deck table is the same small size
    - fix: the gallery reveals as you scroll, and the source picker settles down
    - fix: a set stops paging, and card grids hold still while images arrive
  • v0.14.0

    Release: v0.14.0
    v0.14.0
    
    Commits since v0.13.0:
    - chore: declare 0.14.0
    - feat: one card pool — Standard becomes a filter, and the wire gets compression
    - feat: data ships as one locked archive, and nothing generated lives in git
  • v0.13.0

    Release: v0.13.0
    v0.13.0
    
    Commits since v0.12.0:
    - chore: declare 0.13.0
    - fix: the starred section reads as a section again, and no source means starred
    - feat: decks carry the day they came to exist, and the gallery can sort by it
    - feat: a precon says which set it came from, and "all" means all
    - feat: the deck gallery filters by source, and can pick several
    - feat: pick the art for a deck you cannot write
    - fix: the Karsten mark stops running into the sim dot
    - fix: one affordance in a search field, not two
    - fix: the card pane's tightest-requirement line renders its pips
  • v0.12.0

    Release: v0.12.0
    v0.12.0
    
    Commits since v0.11.1:
    - feat: preconstructed decks, imported from MTGJSON
    - fix: a deck tile's backdrop image loads lazily, like the crop in front of it
    - docs: AGENTS.md is the operator's guide again
    - refactor: decks are organized by source, and answer to their names
    - feat: generated data moves to the package registry, pinned by hash
    - refactor: one card loader, so a per-card fact is stamped once
  • v0.11.1

    Release: v0.11.1
    v0.11.1
    
    Commits since v0.11.0:
    - feat: lint reports sim coverage, so nobody learns it from a refusal
    - fix: respelling the call mints no fresh runs, and four refusals end the turn
    - feat: compare_decks answers the question Gemini kept measuring at
    - fix: a turn that loops through refusals loses its tools
    - fix: the third identical call is refused, because the second changed nothing
    - fix: the Block union narrows again — head is its own member
    - fix: a heading renders as a bold line, since Gemini writes them regardless
    - fix: edit_deck stops answering questions, and get_card starts
    - fix: one flaked request no longer ends the conversation
  • v0.11.0

    Release: v0.11.0
    v0.11.0
    
    Commits since v0.10.0:
    - fix: a billion Plains is 999 Plains at every door
    - perf: the palette guide loads when theming starts, not on every turn
    - fix: the sort keys come from the page, and the prompt says one thing once
    - feat: the answers render their lists, and search ranks like the browser
    - fix: the review's findings — a quantity cap, a scrubbed prompt, an encoded printing
    - docs: the changelog entry covers the release it declares
    - style: Appearance follows Tutor, and Save sits beside Test
    - fix: settings fills its column, and stops asking questions it cannot answer
    - fix: the theme chips show their own colors, and settings stops whispering
    - style: the picker is made of the composer, not the conversation
    - fix: the card picker ranks names the way the card browser does
    - feat: the card picker says what each row costs and what it is
    - style: the keys line reads at one step up, with air between the pairs
    - fix: five things about the picker and the box under it
    - feat: the picker floats, and shows you the card you are picking
    - feat: the owl looks over the top of the conversation
    - feat: the owl reads at the size it ships at
    - refactor: trim the exports nothing calls
    - docs: the host list correction reaches the changelog
    - fix: the about page names every host, and stops claiming your decks stay put
    - fix: the owl carries the same weight as the icons beside it
    - refactor: the quiet action at the end of a row is one style
    - feat: Tutor gets a mark of its own, a paper owl
    - chore: declare 0.11.0, the release where Tutor sees the page
    - fix: the composer trigger nearest the caret wins
    - fix: the card block counts artworks, and an adventure has no back
    - fix: a deck name means the same deck to every tool that takes one
    - fix: the rail's gutter is one value, so its right edge lines up
    - fix: the conversation list read as brackets, and hid its own timestamps
    - feat: $ picks a set, ! picks a format, and hydrate stops writing state
    - fix: one conversation for the whole app, and a list of the saved ones
    - refactor: tool descriptions join arrays instead of concatenating
    - feat: Tutor builds a deck from anywhere, and can take you to a page
    - docs: the rule is context per surface, tools shared
    - feat: every surface tells Tutor what is on it
    - feat: Tutor can show a card, read a set, and say which decks could run one
    - fix: search_cards told the model its own syntax did not exist
    - fix: the boot strip goes to the top of the window and says so plainly
  • v0.10.0

    Release: v0.10.0
    v0.10.0
    
    Commits since v0.9.0:
    - chore: declare 0.10.0, the release where the cards talk
    - fix: a short deck name was faded out to nothing
    - feat: hovering a named card shows it
    - docs: how a named card becomes a link
    - feat: a card that names another card now links to it
  • v0.9.0

    Release: v0.9.0
    v0.9.0
    
    Commits since v0.8.1:
    - chore: declare 0.9.0, the release where the art joins
    - fix: a step through search results paid for the whole search again
    - feat: nine LTR scenes, and the proposer credits a run split across scenes
    - feat: scene captions under their cards, a centered walk, and a Back that knows where
    - feat: the scene page shows whole cards and nothing else
    - feat: scenes, the art that continues across cards
  • v0.8.1

    Release: v0.8.1
    v0.8.1
    
    Commits since v0.8.0:
    - chore: declare 0.8.1, the printing every surface means
    - fix: an artist search shows the art that artist drew
    - fix: every surface lands on the printing it showed you
    - fix: the card sliding in stopped a few percent short of full size
  • v0.8.0

    Release: v0.8.0
    v0.8.0
    
    Commits since v0.7.2:
    - docs: the changelog entry read as a second MR body
    - fix: a sort the app does not have rode the URL into the walk
    - fix: a second touch during the handover was wiped when it landed
    - fix: a query that fit still faded at its end
    - fix: the walker's query wore a different face than the set name
    - fix: the deck button reads small and its icon sat off the text
    - fix: the centered card column sized to its content, not its track
    - fix: a long query in the walker pushed the card column past the page
    - fix: stop the walker deciding how wide the card column is
    - refactor: one faded end, in the design system
    - fix: the stepper's query pushed the page wide, and the swap flickered
    - refactor: drop the card pane's hover lift
    - refactor: the stage owns the element it moves
    - fix: the pane's card eased itself back on from off screen after landing
    - fix: the card that arrived slid back out from under its replacement
    - feat: a committed swipe carries the card off instead of springing back first
    - docs: split three paragraphs the prose linter had been undercounting
    - feat: walks stop at their ends, the puck is always up, and a step costs more
    - refactor: one stage for a card and its neighbors, wherever the list comes from
    - fix: a clipped neighbor with no reserved shape looks like a missing one
    - fix: the neighbors never moved, and the pane scrolled to a card that was not there
    - feat: a lint line opens its card, like every other way of asking for one
    - feat: the deck's card pane scrolls into view when you open it
    - feat: the card sticks to your thumb and the next one comes in beside it
    - feat: the next card comes into view as you drag toward it
    - fix: the wall gave back so little travel it read as a dead card
    - docs: the hint and what moves under the finger
    - feat: the swipe shows what it will do before you let go
    - chore: declare 0.8.0, the search walk and swipe navigation
    - feat: the card page walks the search you arrived on
    - feat: a swipe walks the list a card sits in
    - fix: a set's page number survives leaving the page
  • v0.7.2

    Release: v0.7.2
    v0.7.2
    
    Commits since v0.7.1:
    - docs: two 0.7.2 sentences carried two ideas each
    - feat: sync goes both ways, and the decks page says where it stands
    - chore: declare 0.7.2, sync symmetry and the decks control
  • v0.7.1

    Release: v0.7.1
    v0.7.1
    
    Commits since v0.7.0:
    - fix: drop a dead import, and clear presence on a Drive reset
    - docs: the 0.7.1 entry names the heads-up and the cadence
    - feat: a deck says when another browser has been editing it
    - feat: the newest edit wins, and the deck says it changed elsewhere
    - docs: the 0.7.1 entry reads like the rest of the file
    - chore: declare 0.7.1, the sync simplification