Releases

Changelog

Every change in every release. Grab the latest from the Releases page.

0.6.5.3

Latest

Fixes

  • Competitive Brawl ranked matches now count toward the Constructed Ranked lifetime and season match stats, including wins, losses, win rate, and streaks. Their constructed rank changes already appeared in the chart; the stats now use the same ranked queue.

0.6.5.2

Fixes

  • Brawl games now show the opponent commander's full color identity in Recent Games, All Games, Game Detail, and the opponent-color summary. Immediate concessions and short games no longer depend on which cards were played, when the commander's identity is available in the local card database.

0.6.5.1

Fixes

  • Fixed an empty console window flashing above other applications every few seconds on Windows. The periodic overlay status check now runs tasklist without creating a visible window.

0.6.5

Startup reliability

  • Added independent Start with Windows/macOS and Open dashboard on launch switches above In-game overlay in Settings. Installed apps can register per-user login startup while remaining in the system tray or menu bar, and automatic browser opening can be disabled without stopping tracking. The existing --no-browser flag remains a one-run override.
  • Windows uses the current user's Run entry and removes it during uninstall; macOS uses an app-owned user LaunchAgent. Source checkouts register their current virtual environment so the same controls remain available in development.

Fixes

  • Future Arena events no longer require a tracker update to avoid being mislabeled. Unknown event IDs from the active match room, EventLanding, or the outgoing EventSetDeckV3 request are preserved as authoritative and humanized for display; deck edits, generic deck attributes, and command-zone inference cannot replace them. Generic identifiers such as Constructed_Event_2026 and new date-suffixed event names also appear under the dashboard's Events filter, and a migration repairs existing rows that were stored as Standard or Brawl.
  • Fixed Restore successfully replacing the database but reporting zero games immediately afterward. Migrated snapshots are now checkpointed and returned to single-file journal mode before the swap, so the first read-only summary can open them without waiting for SQLite to recreate WAL sidecars.
  • Fixed Powered Cube matches being stored as generic Draft or even Brawl when Arena supplied CubeDraft_Powered_* as both the queue and event name. Cube event IDs now outrank deck attributes and command-zone inference, display as Powered Cube, and a migration repairs affected stored matches.
  • Fixed Recent Games, All Games, and opponent history repainting older draft games with the colors of the newest revision sharing that deck name. Game rows now derive colors from their own submitted game_deck_cards snapshot.
  • Prevented duplicate tracker processes on Windows and macOS. The unified launcher now acquires an OS-owned single-instance guard before starting the tracker, dashboard, or tray; a second manual launch reports that Tapps Tracker is already running, while a duplicate login launch exits quietly. Crashes release the guard automatically, and Deck Finder remains independently launchable from the running app.
  • Fixed macOS overlay and app builds failing with npm: command not found when Node is installed through nvm but the build runs from a noninteractive shell. The shell build scripts now load the configured nvm default and validate the required Node 18+ toolchain before building.
  • Fixed the macOS 27 overlay disappearing as soon as it starts. The newer lsappinfo output can include extra properties or return no frontmost app; the overlay now reads the foreground application from macOS's native NSWorkspace API instead of deciding Arena is never in front and hiding.
  • Fixed the Settings page changing the overlay to off shortly after a tracker restart when an existing overlay singleton handled the new launch. The tracker now recognizes that existing process, and only an explicit Quit overlay action disables future automatic launches.
  • Fixed the overlay settings getting an unnecessary vertical scrollbar when opened beside the minimal rail. The flyout now receives the full window height after the rail's display scaling is removed.
  • macOS app bundles now identify themselves to the system and menu-bar managers as Tapps Tracker and declare their menu-bar-only activation policy. The bundle filename, executable name and identifier remain stable for upgrades. A new scripts/build_macos_app.sh --fast path makes it easier to test current source with that native identity; direct terminal launches remain Python processes.

0.6.4

Backup & restore

Everything the tracker knows in one file. Settings → Backup & restore writes a .tappsbackup and restores, merges or deletes one — made for the week away from home: back up on the desktop, restore on the laptop, play, then bring the week's games back.

  • What a backup holds. A consistent snapshot of the game database (taken with SQLite's own backup API, with the raw-payload diagnostics buffer left out, then compressed — about 15 MB for a thousand games), settings.json, your Deck Finder creators and the overlay's preferences. Include API keys (on by default) decides whether the Deck AI key travels in the file.
  • The backup folder. Any folder works, and the card offers the Google Drive, iCloud Drive, Dropbox and OneDrive folders it finds on this machine as chips — a chip fills the path in, Set remembers it, and nothing is created on disk until the first backup lands there. Choose one a sync client mirrors and the file turns up on your other computer by itself; nothing in the tracker talks to any cloud service.
  • Restore says what it would do before it does anything — adds 7 games this computer does not have, or would drop 12 games recorded here that the backup lacks, which needs REPLACE typed — then pauses the tracker, saves a copy of the current state (an Undo button puts it straight back), brings the snapshot up to this build's schema, swaps it in, and restores your settings while keeping this computer's own dashboard port, window size and backup folder. A backup written by a newer tracker is refused, with the reason.
  • Merge is for history recorded on two computers: it adds a backup's games to the ones already here and removes nothing, so one more backup afterwards holds everything. Games, sessions and matches can never collide between machines — their ids come from the tracker session that recorded them — so a merge is a plain union; cards are matched by name, and merging the same backup twice adds nothing.
  • Backup Files lists what is in the folder (date, computer, games, newest game, size) with Open location, Restore, Merge and a red × on each. Restore, merge and delete all ask first, naming the file and what will happen; only files inside your backup folder can be deleted from the card. The field below does the same for a file anywhere else on disk.
  • Windows: the database swap waits out a file the system still has open instead of failing, and never lands a restored database beside the old one's write-ahead log.
  • From a terminal: python -m mtga_tracker.backup export|inspect|restore|merge|delete|list|folders.

Automatic backups after each session, and Google Drive over its own API for machines with no sync client, are the next steps (plan).

Fixes

  • The Live Scoreboard's color pips never lit. The tracker's play events carry the display name the timeline prints — Mountain (Land), Smaug the Magnificent (Creature 6/6) — and the scoreboard looked that whole string up for its colors, which no card database matches, so both players' pips stayed blank for the entire game (the archetype guess, which matches cards differently, still worked). Colors are now looked up by the bare card name, and a basic land lights the pips on turn one again.

Docs

  • README, Quick Start, agent guidance and the log, card-database and scry references reconciled with the implementation: the README lists current features and reference guides only. The completed release and overlay plans are replaced by the release guide and the overlay guide, unfinished plans keep only their remaining work behind an index, and the Linux plan gained discovery, desktop, packaging and real-system validation gates.

0.6.3

In-game overlay

A small always-on-top window beside Arena that shows the library the tracker knows and the odds of what you draw next. It is on from the first launch, docked to the left edge; turn it off from Settings → In-game overlay or the menu bar's Stop Overlay.

  • The rail. A slim strip docked to the left or right screen edge (or floating) with the app's card mark at the top and three cells — Turn, Land (the chance your next draw is a land) and Deck (cards left of the deck, with a bar that turns yellow once half the deck is gone and red under 15 cards) — plus an arrow that opens the panel and a ⚙ that opens the settings beside the rail, without unfolding the panel. When the tracker isn't reachable the card mark greys out and carries a warning badge with the reason. The card mark is a vector drawing, sharp at any size and display scale.
  • The panel. The full decklist, one row per card: name over mana cost on the left, copies left over next-draw odds centred in a darker band on the right. Hover a row for the card itself, beside the panel and nearly the width of the gutter, with the odds of drawing it next, within 2 and within 3 under the image; the row lights up while the cursor is on it and the card goes the moment it leaves — no clicking (the overlay never takes focus, so the shell watches the real cursor and tells the page where it is). Lands fold into one row that opens to indented Basic / Nonbasic rows; in Brawl, drawn singletons collapse into a Drawn group; a Sideboard row lists what is boarded. Above the list: land-drop odds for the next one, two and three draws, and a Play/Draw pill. Sort by odds, mana value or name; toggle card names in their colour. Odds are whole percentages. The final library stays up through Arena's results screen, marked FINAL, and clears when you leave it.
  • On, off, pinned. The arrow (or the hotkey) turns the panel on; its chevron turns it off; the pin holds it out. It starts pinned: an opened panel stays until you unpin it. Unpinned, the rail is the folded panel: hovering the rail unfolds it, and it folds back once the cursor has been off it for the return delay. Off, the rail is just a rail. All three are remembered game to game and across launches. Between games the panel folds away; a pinned one comes straight back when the next game starts.
  • Where it lives. Only while Arena is running, on Arena's screen — over a fullscreen Arena too on macOS — and it steps aside while Arena isn't the front window. Flush with the screen edge, with a few pixels of plain ground between the text and the edge; drag it up or down the edge and it snaps back flush the moment you let go. Windows: exclusive-fullscreen covers every overlay; use windowed or borderless.
  • Look and settings (the ⚙ menu, which opens beside the panel or the rail — never over the decklist): a charcoal tint with hairlines between rows and no box border. Scale from 50 % to 200 %; Rail opacity (default 90 %) and Panel opacity (default 80 %), which drive only the tint — text is always solid; Max panel height in pixels (default 800, always capped by the screen; the list scrolls inside); dock; click-through; density; the hotkeys — Alt+Shift+T / ⌥⇧T toggles the panel, Alt+Shift+H / ⌥⇧H hides the overlay — and a Restore defaults button that puts every preference back (the window's position and the panel's on/pinned state stay).
  • From the tracker. The Settings page shows one card — Overlay is on / Overlay is off, one sentence, and a Turn on / Turn off button — over the hotkeys; off means nothing runs and nothing starts with the tracker until it is turned on again. The menu bar shows an Overlay: Running / Stopped line under the tracker's, with Start/Stop Overlay and Overlay Settings in their own section; the overlay adds no menu-bar icon of its own.
  • Works in every game, tracked or not. Jump In, Midweek Magic, Welcome Deck Duels and practice games against Sparky stay out of your stats as before, but the overlay follows them like any other game — the library and the odds are just as useful there. (The tracker's live row, which the overlay and the Live Scoreboard read, is kept current during those games; nothing from them is saved as history.)
  • What it reads and what it costs. A separate native app (Tauri v2, a Preact page, about 5 MB) shipped inside the tracker. It polls this tracker's local GET /api/overlay three times a second during a game and loads card images from Scryfall on hover — nothing else, and never the game itself. An unchanged poll is one indexed read on a kept-open connection (about 0.05 ms); the tracker reads Arena's log four times a second and a check with nothing new costs about 0.01 ms.
  • Building from source needs Rust: scripts/build_overlay.sh (or .ps1); --fast makes an incremental iteration build in seconds. Release builds include the overlay.
  • GET /api/overlay: the library the tracker knows (deck minus what has left it, from the kept opening hand on), per-card hypergeometric odds, land-drop odds, format, opponent, turn, play/draw and the head-to-head record — with an ETag so unchanged states answer 304.

New

  • Scry is tracked. Every scry is counted per seat — how many scries, how many cards they looked at, and how many went to the top vs the bottom — for both you and the opponent (Arena lists the card ids even when the opponent's cards stay hidden). The timeline line says what actually happened instead of a bare "scried": You: scried 2 — kept [Opt] on top, bottomed [Plains] (the opponent's reads scried 2 — 1 top, 1 bottom), with its own Scry badge in the game timeline and the Live Feed. The game page and the deck page get a Scry group in Combat & Resources, under Cards: Scried, Cards scried, Scried Top and Scried Bottom, the last two with their share of everything scried alongside ("1 (33%)"); Removal moves to lead the next column so the four columns stay close to even. Which cards were kept or bottomed is recorded per scry but not shown yet. Historical games get their scry count back from their timelines (the old lines carry no amounts, so their card totals stay blank). Surveil is not yet counted.
  • Recent Games, its Bo3 match rows, and Sessions load 30 rows instead of 25, so the tables' 15-a-page paging shows two full pages.
  • Wins vs Losses on the Overview gets an Avg Game Time column, and its blurb (and the empty-state notes on the game and deck pages) no longer talk about "telemetry" or what early tracker versions did not record.
  • The Deck AI description on the Settings page is three sentences instead of a wall.

Fixes

  • The Live Scoreboard lost the previous game at midnight. Its "today's games" list went by calendar day, so a game played at 23:58 had no outcome and no record at 00:05 and the Previous Game chip went blank. The list now also carries the current tracker session's games and always the most recent finished game.
  • "Card #N" rows that never resolve. A draw could be recorded against an ability object standing in for the drawn card, so the deck stats kept a Card #1156-style row no card database could ever name, and Database Health flagged it forever as a manual UNKNOWN_CARD_LABEL. The draw is still counted but no longer recorded under a placeholder (a diagnostic line says what was seen), and the audit now asks Arena's card database whether N is a card at all: ids that are not become repairable, and db_audit --repair removes those rows. Placeholders for real cards the local database has not learned yet still heal themselves on a later launch.
  • A stray "OperationalError: unable to open database file" on the Live Scoreboard. A read-only open of the database can lose a race with the tracker's own WAL checkpoint, and a Mac app launched from Finder starts with only 256 open files for Qt, the dashboard's per-request connections and the browser's sockets to share — SQLite reports both as the same unhelpful message. Read-only opens now retry once, the app lifts its open-file limit at startup, and a failure that survives the retry is written to data/logs/dashboard-errors.log with the file, WAL and descriptor state that explains it.
  • Windows: the tray menu could hide Quit under the taskbar. A right-click on the tray icon opened the menu downward from a cursor at the very bottom of the screen. The menu now opens upward (and leftward at the right edge) whenever it would not fit.
  • A blank deck-art tile. The signature-card tile only showed its type-colored frame after both art requests had reported failure; a Scryfall image request that stalls or answers 503 without the browser ever raising an error left an empty box with no art and no frame. The frame is now the tile's base layer and the art fades in over it once it has actually loaded; a request that has neither loaded nor failed after six seconds is treated as failed and the by-name fallback is tried.
  • The packaged app's Deck Finder page was blank. The installed tracker did not carry the deck-site modules the Deck Finder loads at runtime (only the terminal Deck Finder analysis did), so the dashboard was offered no sites and drew an empty page. The installers now include them — the build refuses to package a tracker whose Deck Finder would have no sites — and if no site can be loaded the page says so, with the reason, instead of showing nothing.
  • Windows: the paths on the Settings page could not be opened. Log DB and the other paths hid the username as ~\AppData\..., which Explorer does not understand. They now read %USERPROFILE%\AppData\..., which still hides the username and pastes straight into Explorer's address bar or a Run box.
  • Windows: upgrading left old files in the install folder. The installer only ever added and replaced files, so a program an earlier version shipped and the new one does not — MTGA Deck Downloader.exe, now folded into the tracker — stayed behind, and so did anything stale in the bundled runtime folder. Setup now clears _internal and that executable before installing. Tracked games and settings live outside the install folder and are untouched. (Unpacking the zip over an older extraction keeps old files the same way; unpack it into a fresh folder.)

Housekeeping

  • One executable. The Deck Finder terminal tool no longer ships as a second program (MTGA Deck Downloader) beside the tracker — on Windows that put two .exes at the top of the install folder, and a PyInstaller program cannot simply be moved into a subfolder the way the overlay's self-contained binary was. It is now a mode of the tracker itself: MTGA Tracker --deck-finder runs the same terminal UI, which is what the dashboard's Deck Finder page launches in a terminal window. The install folder is MTGA Tracker.exe plus _internal, and the download is a little smaller for not carrying the second copy.
  • Fewer "unknown log entry" diagnostics. Arena's ordinary client chatter — its own requests (==> GetFormats …), the server's answers, scene changes, and the connection and startup notes — is now named for what it is instead of landing in mtga_tracker_unhandled_annotations.log and the raw-payload archive on every launch (dozens of entries per session, hundreds over a day of tab-switching). Nothing about tracking changes: every line was and is still processed; the diagnostic file now holds only things the tracker has genuinely never seen. The archive gets cleaned up too: a one-time pass drops the chatter already stored (then compacts the file), and from now on archived payloads are kept for 30 days — it is a diagnostics buffer, nothing reads it back after that.
  • tappstracker.com rebuilds itself whenever this changelog changes on main.

Docs

  • Plans for Linux support (Arena under Steam/Proton or Wine, phased so CI verifies it before a Linux desktop exists) and for scry/surveil tracking (the scry half is shipped above).

0.6.2

Windows installer — read this if Defender complains

Windows Defender has been quarantining MTGA Tracker.exe from the 0.6.1 installer as Trojan:Win32/Wacatac.B!ml (sometimes .C!ml). The tracker is not malware; the !ml suffix marks a machine-learning guess, not a match against anything known, and it fires on unsigned PyInstaller apps constantly. The shape of this one is exactly what the heuristics distrust: a freshly built, unsigned executable with no publisher that tails another program's log, runs a local web server, launches helper processes, and — for the collection exporter — reads Arena's memory.

This release does the two free things that help:

  • The PyInstaller bootloader is compiled from source on the build machine instead of shipping the prebuilt one that every PyInstaller-packed trojan also ships, so the exe no longer shares those bytes with them.
  • Both executables carry a real version resource (company, product, description, version) — an anonymous exe scores worse than a described one.

Signing the binaries is the only complete cure and it costs money every year, so it is not happening for a free tool; each release is instead submitted to Microsoft as a false positive, which clears that build within a day or two. If Defender has already quarantined your install: Windows Security → Protection history → the Wacatac entry → Restore, then Allow on device, or reinstall after the verdict clears. Details in QUICKSTART.

Performance

Measured on a ~1000-game database. Numbers are cold loads from the tracker itself; a warm dashboard is faster still.

  • Overview: 803 ms → 227 ms (about a quarter of the time). All Games and deck pages load in under half the time; the opponent page in about a fifth.
  • Refreshes between games answer in ~8 ms instead of recomputing everything. Read endpoints are memoized against a fingerprint of the analytics tables; the tracker's heartbeat doesn't invalidate it, while a finished game, a saved note, or an AI archetype landing invalidates it immediately (60-second ceiling either way).
  • How: six new indexes (participants by game/role/deck, deck cards by participant and zone, opening hands and draws by participant, games by match), one set-based draw-quality pass for the overview and All Games instead of one query per game, and a cached split-card name lookup for exports. Existing databases pick up the indexes at their next launch — a one-time build of about 0.3 s.

New

  • Wildcards on the Overview, beside the deck search: common, uncommon, rare, and mythic counts read from the inventory block Arena writes to its log at launch and on every event join (gold, gems, and vault progress are stored too). Nothing shows until the tracker has seen one.
  • Live Scoreboard shows your lifetime record against the opponent's commander in Brawl, one line per commander, hidden until you've faced it.
  • The menu-bar item is now Live Scoreboard, matching the page.

Fixes

  • Opponent colour pips could stay blank until turn 7. When Arena's card database wasn't readable at the moment the tracker built its colour index, the index was cached for the session with only cards from earlier games. It now keeps retrying Arena's layers until they answer, looks up unknown cards on demand, and basic lands light their colour on turn one.
  • The scoreboard's "Looks like…" guess could flip to an impossible archetype (Gruul → Mono-Red after a Forest). Lands no longer count as evidence, and a guess whose colours contradict the table is dropped.
  • All Games flood/screw badges disagreed with the game page for a couple dozen games — the list ignored ramped lands and the real land ratio. Both now use the same rules.
  • Profile and combat columns were blank for decks past the 40th. The Decks table lists up to 100 decks but its combat telemetry stopped at 40, so players with many small decks saw dashes on rows with plenty of games.

Docs

  • README, Quick Start, and AGENTS refreshed; the in-game overlay plan rewritten for Tauri v2 with the rail/panel design mockup (the completed design is now documented in the overlay guide). The overlay itself shipped subsequently in 0.6.3.

0.6.1

  • Renamed to Tapps Tracker everywhere you see it (menu bar, dashboard, window titles). App bundles, commands, and data folders are unchanged, so nothing moves on your machine.
  • Brawl: commanders everywhere. Game pages open with a commander-vs- commander strip and the Opening Hand names your commander (hover for the card); deck pages use the commander as the deck's signature art, add a slim commander banner above the decklist, and list the Opponent Commanders you've faced with your record against each. The overview's Brawl section is always visible (own nav entry) with Best Commander and Toughest Opponent Commander boxes backed by card art.
  • Brawl: decklists include the commander. Arena's submitted maindeck leaves the commander out, so a Brawl list now shows all of its cards; Arena exports gain a Commander section, and the commander's Games Seen is 100% — it is in the command zone every game. Scoreboard colors seed from the commander the moment it is revealed. (Brawl is recognized from Arena's match format, never from deck size.)
  • Fixed: Expected Lands used a flat 40% heuristic on the game page and an older decklist version on the deck page. The game page now uses the decklist submitted for that game (or the deck's nearest one); the deck page uses the newest decklist's land ratio; the label says est. only when no decklist exists at all.
  • Draw Quality reworked. Game page: Total Cards Drawn, Total Cards Seen, Lands Drawn, Lands Seen, Expected Lands, Longest Land Streak, Draw Status on one line, land percentages in the labels. The 8-draw-window and low-land- drought boxes are gone — the flood/screw evidence line already says it in words. Deck page shows per-game land averages with the share beside each label.
  • Opponent mulligans are tracked. Arena reports mulligans for both seats; the game page Mulligans box reads You / Opp. Games tracked before this release show a dash for the opponent.
  • Bo3 matches count once in opponent counts and the opponents list; the opponent page rolls each match into one expandable row with a Matches card. All Opponents is its own page with a back link, a search box that shows the count, and gold focus rings on every filter control.
  • Two-tier format filters on Recent Games and All Games: family pills (Standard, Historic, Modern, Pioneer, Timeless, Limited, Brawl, Events) with fly-out queue and Bo1/Bo3 refinements. All Games drops the redundant format dropdown and search box, widens the deck picker, and shows 30 rows.
  • Deck AI transparency. Settings, the Settings dialog, and the README now state exactly what the API key is used for: one small request per completed game, after the game ends, containing only the names of the cards your opponent revealed — never your deck, account, or log. Scoreboard colors and the mid-game deck label are computed locally and never use the key.
  • Live Log is now Live Scoreboard; the scoreboard keeps the previous game up across reloads with a "Waiting for next match…" pill; Stop Tracking shows as stopped immediately; Deck Finder pills stay lit for the current results.
  • Fixed: blank opponent color pips — the color index no longer caches an empty result when the analytics database is busy at startup, and it reads Arena's renamed Localizations table.
  • Release workflow actions bumped to their Node 24 majors; macos-debug.md documents the macOS "icon shudders and quits" launch failure and its fix.

0.6.0

  • Live Scoreboard. During a game the /live page shows your lifetime and today's record with the current deck, head-to-head record against the opponent, lands played per side, a ramp-aware draw-quality strip, a per-turn timer, your rank on ranked queues, and a best guess at the opponent's archetype from their revealed cards (matched locally against earlier identified games — no network). Between games the previous game's final scoreboard stays up with a Previous Game chip showing the result.
  • Opponents. New Opponents section on the overview: your five most-faced opponents with records, plus your record by opponent color combination — and a searchable Opponents page listing everyone you've ever been paired against.
  • Fixed: a handful of games recorded you as your own opponent. A migration cleans up the historical rows.
  • Removal accuracy overhaul. Removal, wipe, bounce, and counter classification audited against the card pool: edicts count as removal, graveyard hate and hand disruption do not, land destruction is excluded, temporary exile counts, and conditional sweepers are judged by outcome (a board wipe only when they actually cleared the board). Three migrations recount every historical game; docs/REMOVAL_CLASSIFICATION.md records every ruling.
  • Play/Draw and mulligan badges replace the old Mulligans column on Recent Games and All Games; All Games gains a Colors column; single gold focus rings on filter controls; consistent section spacing throughout.
  • Fixed: stopping the tracker from the menu bar now flips the dashboard's tracker state to off immediately; the All Opponents page no longer errors on load.
  • Restart the tracker after updating — migrations run at startup.

0.5.9.2

  • Fixed: exports could grab a deck instead of your collection. Arena keeps deck objects in memory that look exactly like a collection block, and the scanner could return one (34 cards exported instead of thousands). Candidate blocks are now gathered across all of Arena's memory and the largest valid one wins; deck-sized blocks are rejected outright.
  • Fixed: missing set codes on non-default installs. The export now finds Arena's card database via the install path Arena announces in its own log, so set codes fill in on any install location — and if the database still can't be found, the export says so instead of quietly shrinking.
  • New: Export for Archidekt. A fourth export format whose Scryfall ID column removes all import ambiguity (Moxfield reads it too). IDs resolve through Scryfall's batch API with fallbacks for Arena's mismatched collector numbers (Alchemy sets, special prints), then cache locally so repeat exports are instant and offline.
  • Card names no longer carry Arena's <nobr> markup in exports.

0.5.9.1

  • Fixed: collection export crashed on Windows with "int() argument must be a string … not 'NoneType'". Windows reports the first memory region at address zero, which the scanner mishandled before reading a single byte — the export never worked on Windows until now. macOS was unaffected.
  • Release versions now come from the git tag (setuptools-scm). The app, installers, and dashboard all derive their version from the v* tag the release was built from — no hand-edited version strings anywhere.

0.5.9

  • Ramped and searched lands now count in Lands Seen. A land pulled from your library straight onto the battlefield — Lumbering Worldwagon fetching a basic, Cultivate, fetch lands, and the like — used to vanish from every land count because it was never "drawn." It now shows up in Total Lands Seen for both live games and, via a one-time backfill of your history, past ones.
  • Fetched lands no longer read as flood, but still protect against screw. A land you searched out on purpose was not drawn against your will, so it is excluded from the flood side of the flood/screw math — ramp-heavy decks stop reading as flooded just for doing what they do. Screw keeps those lands, because a land you have (even a fetched one) is still mana in play and makes a mana-screw reading correctly less likely.
  • Export your MTGA collection from the Settings page — three buttons (.json, .csv, .txt) that read your full card collection out of the running game and write a file you can import into Moxfield and similar sites. Arena must be running with the collection loaded (open the Decks tab once); on macOS an administrator prompt appears, since reading another app's memory needs elevated access. Anchors are derived automatically from your own tracked decklists — nothing to type — and a second export within a few minutes reuses the first scan (no repeat prompt). Extraction technique adapted from NthPhantom10's MTGA-collection-exporter.

0.5.8

  • Live Log is now the Scoreboard — the old Qt play-by-play window is replaced by a live page in the dashboard (#/live): a hero scoreboard with both life totals, color pips, and deck name, a friendly format chip, the turn and game clock, and Brawl commander art with hover previews. Below it, a Live Feed that renders through the exact same timeline component as the /game page (so it reads identically), the current game's play-by-play, a retained "Previous Game" between matches with a closing "Game ended" banner, a session rail (record, runtime, live/ready status), and a scrolling Today's Games list. The Qt window is now a buried debug fallback (MTGA_TRACKER_QT_LOG=1).
  • Deck Finder moved into the dashboard — no more separate terminal window. Pick a site then a format, browse a per-site results table (win rates for untapped.gg, event placings for tournament sites, and so on), open any deck to export it to Arena or jump to the source, or hit "Surprise Me". Creator lists moved to the Settings page.
  • Settings is now a dashboard page (#/settings, gear icon on every page): Deck AI configuration, Deck Finder creators, a tracker-status readout (monitoring/card DB/log DB/version), a single sun/moon theme toggle, and the Database Health link — all in the web UI. The old Qt dialog remains as a fallback.
  • Colorless is a color: the colorless diamond ("C") now shows wherever colors do — Recent Games, the Decks table, deck and game pages, and the live scoreboard — for decks and opponents whose known cards are all colorless (Eldrazi, artifact decks), instead of showing nothing.
  • Sidebar & navigation: a Live Log entry above Overview that turns green while the tracker runs and red when it's stopped, an icon on every nav item (icon-only when the rail is collapsed), a Deck Finder button with a magnifier, and a global search that finds cards or decks.
  • Deck colors everywhere: color pips on the deck page header, a Colors column on the overview Decks table, and a Colors column in Recent Games (between Deck and Format). Colors are judged lands-first from real casting requirements — land identities carry double weight, hybrid pips ({U/B}) never force a color, a single off-color card never counts, and decks tracked before decklist capture fall back to the cards they were seen playing, so every deck gets pips.
  • Card page overhaul: sections reordered (Summary, Opening Hand Impact, opponent impact, Played By Side, Repeat Draws, Opponent Repeat Draws, Your Decks), an Avg Per Game metric, the same ambient card-art backdrop as the deck page, and a new "Opponent Could Have Played It" panel — games where the opponent's revealed colors could cast the card, how often they actually did, and the appearance rate. Computed live from existing data, no backfill.
  • Recent Games: the Match Record column is gone from the top level (a win is a win) — expanding a Bo3 match shows "Match record: 2–1" in the flyout instead.
  • Deck page polish: hero-sized signature art (with a by-name Scryfall fallback for new sets whose Arena-ID mapping hasn't landed yet), the Copy Arena Deck button moved into the topbar beside the card search, and Decklist Changes moved down between Vs Opponent Colors and Recent Games.
  • Overview: the deck page's Land Statistics (Normal/Flood/Screw split across all classified games) now heads the land section, Opponent Meta pages at 10 rows instead of silently cutting at 15, and the Decks table dropped Life Gained / Game to stop horizontal scrolling.
  • Fit and finish: Combat & Resources "(N drawn)" counts render as small muted one-line suffixes instead of wrapping, the card-search focus ring is a single clean accent border, pages scroll clear of the Back to top pill, official card-type symbols (chalice, claw mark, sunrise…) with singular labels in the deck-list type boxes, and "Imported Deck" games retitle themselves the moment the renamed deck's first game lands instead of waiting for a tracker restart.

0.5.7

Rolls up everything since 0.5.5 (including the 0.5.6 beta's date repair).

  • Mana columns everywhere cards are listed: the deck page's Deck List & Sideboard, and the game page's Opening Hand, Drawn Cards, Cards Played, and Opponent Deck tables all show each card's cost with official symbols.
  • Opponent Deck on the game page replaces "Opponent Revealed Cards", split into Opponent Played Cards (with the turn(s) each copy hit, like your own Cards Played table) and Opponent Revealed Cards (visible draws, discards, mills, exiles).
  • Table totals: proper totals rows on the deck list and sideboard, and on the game page's Drawn Cards, Cards Played, and Opponent Deck tables.
  • Mana costs on the deck list: a new Mana column (between Card and Type) shows each card's cost with the official MTG symbols — hybrid, twobrid, Phyrexian, X, the lot — rendered from a bundled icon font (mana-font), no network needed. Costs come from Arena's own local card database (backfilled into the tracker's cards table at startup and after each game, like color identities already were), with a browser-cached Scryfall lookup as fallback for anything Arena's DB doesn't cover. Works for every deck retroactively.
  • Deck list at a glance: MTGA-style card-type count boxes (Planeswalkers → Lands) above the deck list, plus "N cards total" lines under the main deck and sideboard tables.
  • Mana-value stats in Combat & Resources on both the game and deck pages: "Mana value / card played" and "Mana spent / turn" for you vs the opponent, computed from printed costs (lands excluded, X = 0) — a low cards-played count with high mana spent per turn reads very differently from four one-drops.
  • Repaired dates stored month/day-swapped by pre-0.5.5 versions for day-first locales: games recorded before the locale-aware parser (e.g. 9 August read as 8 September) landed months in the future and scrambled every date-sorted view. A one-time migration swaps them back using each tracker session's system-clock start time as the anchor — conservative by design, ambiguous rows are left untouched. Covers games, matches, turns, events, console logs, rank snapshots, and the payload archive. No database reset needed.

0.5.5

Brawl

  • Brawl is now a first-class format: commander win-rate tables on the Overview (your commanders and the ones you faced), an overall and per-queue record strip, Brawl queue labels plus commander matchup rows in Recent Games, and the commander tables page at 8 rows. The Competitive Brawl queue keeps its label even when Arena's deck attributes disagree, and Standard/Historic/ranked Brawl stay distinct everywhere.

Per-game combat & resource stats

  • New tracked categories on the game page — Removal (spot removal and board wipes played, with your drawn counts folded in, plus creatures/non-creatures lost to removal), Bounce (bounce cards played, permanents bounced to hand), Land Destruction (lands destroyed, successfully replaced by a land drop, lost for good, and the replacement rate), Counter Magic (counters played, and — from the actual stack outcome — how many landed vs failed), Tokens (created / destroyed / sacrificed / exiled per seat), and Poison counters. Card roles are classified from Arena rules text, so removal counts from the first game a card is drawn.
  • Historical games are backfilled automatically: a one-time migration recomputes the behavioral stats (removed/bounced permanents, lands, countered spells) for every old game from its recorded timeline, and scripts/backfill_card_role_stats.py fills the classification-based columns using the local Arena card database. Stats that genuinely cannot be reconstructed (tokens, poison, opponents' draws) show a dash rather than a fake zero.
  • Outcome reasons now detect decked, poisoned, and timeout endings that were previously labeled as concessions, and concede labels are short ("Opponent conceded" / "You conceded").

Deck page

  • Combat & Resources on the deck page: every game-page category as per-seat, per-game averages, in the identical column layout (the game and deck pages now share one deterministic arrangement instead of height-balanced masonry).
  • New Turn Timing (average your/opponent turn time per game and per turn) and Draw Quality (average cards and lands seen/drawn, expected land rate) sections; Formats became win-rate rectangles per queue with BO1/BO3 labels; Vs Opponent Colors opens with Best Against / Worst Against highlight cards.
  • The page picks up an ambient background tinted from the signature card's art, and metric cards across the deck and game pages gained icons.
  • Deck identity can no longer be misattributed: the decklist actually submitted to a game now arbitrates which deck the game belongs to, fixing games recorded under a previously-played deck's name when the tracker launched mid-queue.

Overview

  • Match-level records everywhere: a Bo3 counts once — top row shows Matches / Wins / Losses / Win Rate / longest streaks with icons, Wins vs Losses splits are colored and Wins-first, and How Games End presents per-reason percentages in side-by-side Wins and Losses tables.
  • Constructed Ranked section with lifetime match stats, a season dropdown, the rank chart, and per-season stats (constructed queues only — ranked Brawl tracks separately). New BO1-Ranked / BO3-Ranked quick filters, a searchable Deck filter, and the win-rate trend now covers the last 30 games.
  • Log timestamps are locale-safe: day/month order is learned from unambiguous entries (with a system-locale fallback), fixing "today's games" sorting between older dates for day-first locales, and dates render in the viewer's locale.

Game page

  • Cards Played shows the turn(s) each card was played, Opponent Revealed Cards shows the reveal turn, Drawn Cards pages at 10 turns, and the Repeat Draws card view always shows the 3 and 4+ buckets — including the opponent's repeat draws.

Fixes & maintenance

  • Fixed DB Health falsely reporting GAME_EVENT_ASSIGNMENT_MISMATCH for post-game tail events (Bo3 sideboarding gaps, rank updates, summary lines) — on a real database every flagged row was a tail and none were misassigned. The old repair also detached those rows, deleting real timeline entries. The finding and repair now only act on events whose timestamp falls inside a different game's window, and the reassignment runs automatically at tracker startup (a new index takes the pass from 4.4s to ~150ms) so nobody needs db_audit --repair by hand.
  • Stopped tracking Welcome Deck Duels (pre-made deck vs pre-made deck, e.g. "Welcome Deck Duels HOB"); migration v15 removes already-saved games of this mode and recomputes session stats. The README's "What isn't tracked" list and the dashboard's format filter are updated to match.
  • A new set's card database is picked up mid-session: after each game the tracker allows one re-scan for a newer Raw_CardDatabase, so set-release day no longer needs a restart when Arena drops the new DB alongside the old one. Arena's card DB is now always opened strictly read-only, so the tracker can never create or modify files in Arena's folder.
  • A concede during the opening mulligan decision is recorded as a real game instead of being skipped as a ghost.
  • Database hygiene: new indexes on the game-events timeline and payload archive, PRAGMA optimize each launch, and scripts/delete_untelemetered_games.py (which now VACUUMs after deleting) to drop early games recorded without combat telemetry.

0.5.4

  • Proper Windows installer: releases now ship MTGA-Tracker-<version>-setup.exe (Inno Setup) with a Start Menu entry, an Apps & Features uninstaller, and in-place upgrades. Installs per-user by default (no admin prompt) with an optional all-users/Program Files mode; uninstall asks before touching your tracked-game data. The portable -windows.zip is still published alongside it.
  • Multi-target spells show every target: Arena sends one TargetSpec annotation per chosen target, and the tracker kept only the last one — Ram Through showed only the creature taking damage, not the attacker dealing it. Targets now merge in selection order. BlockerDeclared annotations got the same hardening (every affected id is treated as a blocker).
  • The install-discovery log parser gained a second, Windows-verified marker (Arena's localization line names a file inside Downloads\Raw directly) and now normalizes Arena's mixed forward/back slashes.
  • The "Resolved N previously unknown card label(s)" message no longer repeats on every launch: duplicate-name placeholder rows are folded into the real card's row once, and only actual changes are counted.
  • Startup output tidied: Detailed Logs state prints only on changes, and one-time maintenance messages appear inside the startup banner instead of after it.

0.5.3

  • Arena installs are now found anywhere — standalone (.msi) installs on any drive included. The tracker reads the install path Arena itself announces in the head of Player.log (the Unity [Subsystems] header, verified against a real log) and derives the card-database folder from it, ahead of the Steam-library and Program Files guesses.
  • Databases recorded without the card DB heal completely. The startup backfill that rewrites Card #N placeholders now also covers mulligan-hand rows, labels with no matching cards row, and duplicate-name collisions — so a user whose install was previously unfindable gets their full history renamed on the first launch after updating. The DB Health finding for these labels now explains that restart-to-fix in plain language.
  • Builds no longer use UPX compression, which was tripping antivirus heuristics on the unsigned Windows executables.
  • Docs: AGENTS.md expanded and corrected as the single agent guide (no CLAUDE.md); added docs/MTGA_INSTALL_DISCOVERY.md.

0.5.2

  • Fixed the Deck Finder button on Windows flashing a console that instantly closed ("...is not recognized as an internal or external command"): cmd.exe cannot parse the backslash-escaped quotes Popen produces for argument lists, so the spaced exe path was split apart. The launcher now builds a single cmd /S /C line using cmd's own quoting rules. Double-clicking the exe always worked; only the menu-bar/dashboard launch was affected.

0.5.1

  • Fixed "Local Card DB: not found" on Windows (cards showing as Card #NNNN): the tracker now reads Steam's libraryfolders.vdf and checks every configured Steam library on every drive (root located via Program Files and the registry), plus Epic Games install paths — on Windows and macOS. When the DB still can't be found, the startup banner explains the consequence and the MTGA_DATA_DIR override.
  • Fixed the packaged Deck Finder starting with "No providers found": its provider modules load dynamically, so PyInstaller never bundled them. The build now collects every submodule and the registry has a frozen-build fallback list guarded by a drift test.
  • Windows path display now uses %USERPROFILE% instead of ~, so locations in the startup banner paste straight into Explorer or cmd.
  • The AI deck guess no longer prints a stray console line after "Ready for next game..." — it lands silently in the game record and shows on Game Detail.

0.5.0

  • Bundled the Deck Finder (MTGA Deck Downloader) as a companion tool: launch it from the menu bar or the dashboard sidebar, browse creator decklists (Moxfield, AetherHub, TCGplayer, magic.gg, MTGO, Untapped) in a sized terminal window, and copy lists in Arena import format. Its dependencies install with the tracker; creator lists live in deckfinder_config.json at the project top level.
  • Added AI opponent-deck identification: with an OpenAI, Anthropic, or Gemini key, one small background call after each completed game names the opponent's archetype by its dominant colors and strategy. Shown as the Opponent Deck Type on Game Detail (color label as fallback); it never blocks live tracking. Reasoning-class OpenAI models are asked for low effort and retried once on token-starved empty replies; failures now surface a real error via scripts/test_deck_ai.py.
  • Added a Settings… dialog to the menu bar app for the AI provider, key, and model, plus a Deck AI status line in the tracker startup banner.
  • Moved settings.json to the project top level next to config.py (installed builds keep it in the app data folder; the old data/settings.json migrates automatically) and anchored the .gitignore config.py pattern so the Deck Finder's config module is tracked.
  • Fixed finished games being overwritten by the next game's data when Arena re-sent a match's final GameOver state after the summary reset.