Pokered Save Editor 2
Pokemon Red & Blue save file editor - Qt 6 C++/QML
Loading...
Searching...
No Matches
Version History — June 2026

← All months (index) · 192 commit(s) this month.


2026-06-22 – Tests: coverage gap-fill pass 1 (db accessors) + export-reachability finding

First Gap-5 coverage-fill pass: tests/db/tst_db_coverage_fill.cpp exercises the Examples / TmHmsDB / MusicDB / TrainersDB accessor one-liners that no existing test happened to call (read-only, zero source changes). Building it surfaced a key reachability limit now documented in plans/testing.md: the db/savefile shared libs only export their DB_AUTOPORT-marked classes, so unexported classes (e.g. Examples, HiddenCoinsDB) are only reachable from a headless test via QML meta-object property() reads (used here for the Examples accessors) — a chunk of the raw coverage "miss" is export-/data-gated, not genuinely fillable. Full ctest 72/72 green. (Test-only; no VERSION change.)

2026-06-22 – Tests: visual-regression floor + BDD/acceptance scenarios

Two new GUI suites (real app shell, headless offscreen). tst_visual_regression grabs every home-reachable screen via the offscreen software renderer (the screenshooter's path) and requires a non-trivial spread of distinct colors — catching the class tst_qml_screens can't: a screen that LOADS clean yet RENDERS BLANK (broken binding, offscreen content, dead provider). Deliberately NOT a pixel-perfect baseline diff (the project treats pixel assertions as a trap during UI polish, and won't commit baseline PNGs); the maps WIP screen is excluded (intentionally unbuilt). tst_acceptance states the two user-level promises as Given/When/Then scenarios over the GuiApp harness: an edited value survives save→close→reopen, and browsing every screen mutates zero save bytes ("Save File Integrity Is Sacred", as acceptance). Full ctest 71/71 green. (Test-only; no VERSION change.) This completes the test-TYPE breadth (the remaining program is the coverage-to-100% push.)

2026-06-22 – Tests: QAbstractItemModelTester model-contract suite (tst_model_tester)

New tests/mvc/tst_model_tester.cpp — wraps every QAbstractItemModel subclass in Qt's own QAbstractItemModelTester, which validates the framework contract (index/parent/rowCount/columnCount/ data/roleNames consistency, valid-vs-invalid index handling) AND the change-signal protocol (beginResetModel/endResetModel, dataChanged, layoutChanged bracketing) that hand-written tests miss. Covers each standalone select/list model freshly constructed, every live Bridge-wired model over the populated BaseSAV fixture, and the dynamic models (Pokedex sort-reset, PC storage box switch, box selector) with a tester attached across the mutation. All models pass clean — no contract violations, now permanently guarded. 5 cases, guiless. Full ctest 69/69 green. (Test-only; no VERSION change.)

2026-06-22 – Tests: QSignalSpy signal/slot suite (tst_signals)

New tests/savefile/tst_signals.cpp — the suite's first dedicated signal/slot coverage. The rest of the suite asserts VALUES; this asserts the notification layer every QML binding depends on: that mutating a fragment emits exactly the right change signal (correct count, and that bound-clamped no-ops still honor their always-emit contract), and that the internal connect() wiring actually fires — verified by spying the DOWNSTREAM signal (PokemonMove ppUpChanged/ppChangedppCapChanged). Also covers PlayerBasics (badgeSet, the targeted randomizers emit exactly one signal, reset() fans out to every field signal). 9 cases, guiless. Full ctest 68/68 green. (Test-only; no VERSION change. Broader model dataChanged/layoutChanged emission is covered structurally by the QAbstractItemModelTester pass.)

2026-06-22 – Fix: new move slots start with 0 PP-Ups (the dead-store, confirmed intended)

Follow-up to the static-analysis pass. The PokemonMove constructor, when filling an empty slot (move == 0), calls randomize() — which assigns a random 0-3 PP-Ups — and was meant to then reset that to 0 so a brand-new move starts clean. The original ppUp = 0 assigned the constructor PARAMETER (which shadows the member), so it was a no-op and new moves silently kept a random PP-Up count. Now writes this->ppUp = 0. Scoped to move construction only — the deliberate "randomize everything" actions are unaffected. Confirmed intended with Twilight. Full ctest green. VERSION 0.14.1-alpha → 0.14.2-alpha (PATCH).

2026-06-22 – Static-analysis gate (clang-tidy + cppcheck + qmllint) + 8 analyzer bug fixes

Added the project's missing static-analysis / linting layer. New repo-root .clang-tidy (a curated, DEFECT-focused check set — clang static analyzer + the high-signal bugprone/performance/unused checks, with the noisy/style families and three deliberate-project-idiom checks documented-OFF), .cppcheck-suppressions, scripts/lint.ps1 + scripts/lint.sh (run clang-tidy over build/compile_commands.json, cppcheck if present, and qmllint — qmllint is informational-only because it can't resolve the project's C++-registered QML types under the no-qt_add_qml_module design; cppcheck is informational too until a validation pass), and a lint GitHub Actions workflow. CMAKE_EXPORT_COMPILE_COMMANDS is now forced ON. clang-tidy runs file-parallel (a serial sweep of ~140 Qt TUs is ~25 min on a 2-core runner) and the gate is clean (143 TUs, 0 findings).

Running it surfaced real defects, now fixed: PokemonBox::expLevelRangePercent() did integer division (curExp / expEnd, both var32) before widening to its float return — the fractional percent was always truncated to 0 until the very top of a level (fixed to float division + a divide-by-zero guard; regression-guarded by a new mid-window assertion in tst_pokemonbox); an unguarded toType1->ind deref in PokemonBox::update()'s type2 else-branch (now guarded, matching the type1 path); a dead store in PokemonMove's ctor (ppUp = 0 assigned the shadowing parameter, a no-op — removed); a signed/unsigned char compare in PokemonStorageSet; an int-multiply widening in WorldScripts::reset(); plus cheap const-ref loop fixes (fontpreviewprovider, eventdbentry, scripts, spriteSet) and a missing switch default in PokedexModel. One latent finding is suppressed + flagged for review: ~ItemMarketEntry() can call the pure-virtual _whichType() (UB) on the unusual path where whichType() was never cached during the object's life — a lifetime refactor of that UAF-historied area, deferred to Twilight. Full ctest 67/67 green. See notes/plans/testing.md → "Static analysis / linting". VERSION 0.14.0-alpha → 0.14.1-alpha (PATCH).

2026-06-17 – Editor: confirm destructive ops, status badge, evo gating, 3-digit level

Informed-consent + glance polish on the Pokémon editor. New reusable fragments/general/ConfirmPopup.qml (centered alert modal — title, body, Cancel/Confirm — matching the storage "Boxes Formatted" warn) with ask(title, body, action, label). One shared popup is threaded (confirmAsk) PokemonDetails → DetailsPages → MovesTab → PokemonMoveSel, so every destructive action now confirms first: whole-mon Re-Roll, Reset, Max Out, Correct Data, Evolve / De-Evolve, the move bulk ops (clear-all-but-first, re-roll all, make all valid), and per-move Delete / Validate. Non-destructive / individual-field actions (Heal, per-move randomize, per-field re-rolls) are unchanged. The Evolution group is hidden entirely when the species can neither evolve nor de-evolve, and each arrow stays disabled when that direction isn't possible. The GlancePane sprite now shows a status-condition badge (sleep / poison / burn / freeze / paralyze) in its upper-right when afflicted (same decode + assets as the storage grid), and the level field fits 3 digits ("100"). QML-only; tst_qml_screens + tst_gui_moves + full ctest (67/67) green; screenshot-verified. VERSION 0.13.1-alpha → 0.14.0-alpha (MINOR — a notable UX/safety feature set).

2026-06-17 – Editor actions: move them into the tab HEADER bar (not the Moves tab)

Follow-up to the previous entry: the mon-wide action groups (Data [Reset | Max Out | Correct Data] and Evolution [← fish →]) moved OUT of the Moves-tab body and INTO the DetailsPages header (accent) bar, right of the General / DV-EV / Moves tabs — so they're visible on every tab, which is the right home for mon-wide actions. Styled light for the accent bar via a new HdrBtn (light icon + light hover wash + light divider), light-bordered groups; the fish centrepiece is a non-interactive Button icon so it tints light reliably. QML-only; tst_qml_screens + tst_gui_moves + full ctest (67/67) green; screenshot-verified. VERSION 0.13.0-alpha → 0.13.1-alpha (PATCH).

2026-06-17 – Pokémon editor: wider preview, Moves-tab actions section (replaces the Toolkit button)

Bundle of editor changes (Twilight's spec). The preview pane (GlancePane: sprite + stats) is ~10% wider — the PokemonDetails split went 62/38 → 58/42. Validate no longer leaves a gap: the per-move validate now calls a new PokemonBox::correctMoveAt(ind) that runs correctMove() (which can clear a duplicate/invalid move) and then compacts the list so the later moves slide up — no hole. The old footer Toolkit menu (Max Out / Correct Data / Reset / Evolve / De-Evolve) is gone; its actions moved into a new actions section below the move rows in the Moves tab: a Data group [Reset · Max Out · Correct Data] (icons down-left-and-up-right-to-center = reset, up-right-and-down-left-from-center = max out, file-circle-check = correct) and an Evolution control [← fish →] (de-evolve / evolve arrows flanking the FA fish). The footer is now Re-Roll + Heal (AppFooterBtn3AppFooterBtn2). New icons downloaded + added to app.qrc (FA already credited). New test box_correctMoveAtCompacts; full ctest (67/67) green; screenshot-verified. VERSION 0.12.5-alpha → 0.13.0-alpha (MINOR — a feature + a screen restructure).

2026-06-17 – Moves tab: aspect-correct (un-squished) action icons, even buttons

The action icons were squished — forced into 18×18 when their FA viewBoxes differ (dice 640×512, file-circle-check 576×512, trash-alt 448×512). Now each is sized to its own aspect at a common height (dice 22×18, file 20×18, trash 16×18) so the glyphs aren't compressed (the dice especially reads wider), and each button carries a uniform Layout.preferredWidth: 36 so the group stays even and lines up with the top bar. Applied to both the per-row reveal and the top-bar bulk group. QML-only; full ctest (67/67) green; screenshot-verified. VERSION 0.12.4-alpha → 0.12.5-alpha (PATCH).

2026-06-17 – Moves tab: align the reveal tool group with the top bar, drop the panel edge

Small alignment/polish on the row tool reveal: the slid-in tool group's rightMargin now matches the top bar's (10), so the per-row [validate | random | delete] buttons line up in the same columns as the top-bar bulk buttons above them (they were ~6px off). Removed the panel's hairline left edge/border effect — the slid-in panel is now just the plain row-coloured backing hiding the value box. QML-only; tst_gui_moves + tst_qml_screens + full ctest (67/67) green; revealed state screenshot-verified. VERSION 0.12.3-alpha → 0.12.4-alpha (PATCH).

2026-06-17 – Moves tab: tool-reveal restyle to match the top bar + file-circle-check

Another polish round on the row tool reveal. The slid-in panel no longer uses a solid accent surface with big stretched (fillWidth) light icons — that read out of place and the leftmost button was wider than the rest. It now uses the row colour as the backing (it just hides the value box behind it, with a hairline left edge) and the tools are the exact same bordered icon group as the tab's top bar (dark icons, even SegBtn widths) so they look native. Validate is now the file-circle-check FontAwesome-free icon (downloaded + added to app.qrc; FA already credited) on BOTH the per-row reveal and the top bar. Reordered to a consistent validate · random · destructive across both: the per-row group is validate / random / delete and the top bar is validate / random / clear-all. QML-only + 1 asset; tst_gui_moves + tst_qml_screens + full ctest (67/67) green; rest + revealed states screenshot-verified. VERSION 0.12.2-alpha → 0.12.3-alpha (PATCH).

2026-06-17 – Moves tab: tool-reveal polish (handle + full-cover accent panel, icon fixes)

Polish on the Moves-tab row tools from review. The hover reveal used to only PARTLY cover the value box (and covered it from a whole-row hover); now a small chevron handle (angle-left) sits in a reserved right-edge lane — the value box stays fully visible/editable at rest — and hovering the handle (or the panel) slides in a SOLID accent-colored tool panel that completely covers the value cluster, with light (white) icons, reading clearly as a revealed tool collection. Icon fixes for consistency: the top-bar clear-all-but-first is now a trash (trash-alt, matching the per-row delete) instead of a broom; make-valid (per-row + top-bar) is now a wand (magic) instead of check-double, which is already the select-all icon. Still an overlay over a clipped row, so no reflow. QML-only; tst_gui_moves + tst_qml_screens + full ctest (67/67) green; rest + revealed states screenshot-verified. VERSION 0.12.1-alpha → 0.12.2-alpha (PATCH).

2026-06-17 – Moves tab: fix PP/PP-Up desync, hover-reveal row actions, GUI tests

Fixes from in-app review of the Moves tab. The PP / PP-Ups views were desyncing — flipping between them (or hitting "max") could mix the two fields. Root cause: one shared text box wrote pp or ppUp depending on the view, and the maximumLength flip on toggle truncated the text into a cross-field write. Fixed by construction: two independent text boxes (one per view, each bound to and writing ONLY its own field), swapped by a StackLayout. The row action buttons (randomize / make-valid / delete) now slide in from the right on hover (an overlay over an opaque row-matched backing — never reflows the row; the row is clipped so they're hidden at rest), reclaiming the row real-estate the user wanted. Dropped the min/reset arrow (kept only the →| max). Added a dedicated tst_gui_moves GUI suite that drives the live editor: toggling the view never mutates data, the PP/PP-Up boxes are independent + write through, and model changes reflect in the right box — plus a model-level move_ppAndPpUpIndependent test. Full ctest 67/67 green (the new GUI test included); both views + the hover reveal screenshot-verified. VERSION 0.12.0-alpha → 0.12.1-alpha (PATCH).

2026-06-17 – Moves tab: PP / PP-Ups dual view, per-move actions, bulk top bar

Big functional pass on the Moves tab (Twilight's spec). Fixed-width columns (type chip 58px, PP editor, actions) so move name + type no longer jitter row-to-row. A tab-level PP / PP-Ups segmented toggle (top bar) flips what every row's editable box edits: current/max PP, or current/max PP-Ups (max 3, typeable) — one view for the whole tab, so it stays consistent as moves are dragged. Each row's value box is flanked by the arrow-to-line |← / →| buttons (set to min 0 / max cap), reusing the DV/EV icons. The ⋮ overflow menu is gone; in its place a per-move connected action group — randomize this move (dice), make valid (check-double), delete (trash). Delete compacts the list (no gaps; later moves slide up) via new PokemonBox::deleteMoveAt(). A top bar carries the view toggle plus three bulk actions: clear-all-but-first (broom → new clearMovesButFirst()), randomize all (dice), make all valid (check-double). All icons already in the FA set + qrc (no downloads). New tests box_deleteMoveAndClearButFirst; tst_qml_screens + full ctest (66/66) green, both views screenshot-verified. VERSION 0.11.0-alpha → 0.12.0-alpha (MINOR — a substantial feature set).

2026-06-17 – Moves tab: fix empty/blank rows from in-app review (id collision, layout, combo sync)

Follow-up to the Moves-tab redesign — in-app review showed the tab rendering empty, which a zero-warning screen-load test can't catch (it only checks for QML warnings, not that rows are visible). Three distinct bugs, found with the headless screenshooter:

  1. Rows collapsed to zero width — the panel used a plain Column with anchors.left/right and delegates bound to width: rowsCol.width; a Column sizes its width FROM its children, so that's circular and collapses to 0. Switched to a ColumnLayout with Layout.fillWidth (mirrors OverviewTab).
  2. monMove always null in every rowMovesTab and PokemonMoveSel BOTH used id: top, and inside the Repeater delegate the inner (PokemonMoveSel) top shadowed the root, so top.boxData resolved to PokemonMoveSel's own null boxData. Renamed the MovesTab root id to movesTab.
  3. Combo showed the wrong move name (right type/PP, wrong name) — brg.moveSelectModel is per-mon and rebuilt async (PokemonDetails.onCompleted → monFromBox switches it to this mon's specific list), so syncing currentIndex inline computed against the wrong model state. Consolidated the sync into a Qt.callLater-deferred syncMoveCombo() that runs after the model settles. Also inlined the row height as a delegate-local constant (reading top.rowH through the root from a delegate went [undefined] transiently and zero-collapsed the row). Verified by rendering the editor's Moves tab (Ember / Mega Punch / Flamethrower / Earthquake, correct types + PP). tst_qml_screens, tst_gui_fidelity, full ctest (66/66) green. QML-only; VERSION unchanged (0.11.0-alpha, unreleased).

2026-06-17 – Pokémon details "Moves" tab: style-language redesign + drag-to-reorder

Brought the Moves tab up to the General/DV-EV style language and made moves reorderable by drag. The four type-colored pills became zebra rows in one white grouped panel (scrollbar-lane reserved); each filled row keeps its type identity via a colored left accent strip + a faint type chip, with the move combo / PP field / / maxPP / ⋮ overflow menu inline (every prior action preserved — PP-Up submenu, per-move restore/re-roll/correct, All-Moves bulk ops). A left grip handle (filled rows only — empties stay parked at the bottom per game move-list compaction) drags a row to reorder: the row content reparents to the window overlay so the ghost floats free, a dashed insertion caret marks the drop slot (top edge = before, bottom = after, so the lower half of the last move appends), and the mutation is deferred a tick — the same mechanics as the Bag list drag. Backed by a new PokemonBox::reorderMove(from, to) (Q_INVOKABLE) that anchor-splices the filled move slots' (id/pp/ppUp) values among the fixed slot objects — the slot QObjects keep their identity so QML's movesAt() pointers stay valid, PP rides with its move, and only the move bytes the reorder touches change (byte-fidelity preserved, confirmed by tst_gui_fidelity). PokemonMoveSel/MovesTab were made fully null-safe on a transient move (the Repeater delegate reads through boxData during build/teardown). New regression test box_reorderMove; tst_qml_screens + tst_gui_fidelity + full ctest (66/66) green. VERSION 0.10.1-alpha → 0.11.0-alpha (MINOR — a whole-tab redesign + a new feature).

2026-06-17 – DV/EV tab polish: arrow-to-line min/max icons, rounded active edges, shiny tweaks

Round of refinements on the new DV/EV tab. The Max/Reset action combo swapped the vertical double-chevrons for horizontal "arrow-to-line" icons|← (reset to 0 / minimum) on the left, →| (max) on the right, dice re-roll between — ordered low→high (two new hand-authored FA-style SVGs, arrow-left-to-line / arrow-right-to-line, added to app.qrc). Fixed the segmented-control "Market" flat-edge — an active end segment's accent fill now follows the group's rounded corner (per-corner topLeftRadius/… on the fill, Qt 6.7+; added a last flag beside first). Future Shiny moved its label above its row, and now shows only on the DV tab (shininess is derived from DVs, so it's meaningless under EVs). EV Max/Reset already shared the DV combo, so both kinds get the new icons identically. QML-only + 2 assets; tst_qml_screens + full ctest green, screenshot-verified. VERSION 0.10.0-alpha → 0.10.1-alpha (PATCH).

2026-06-17 – Pokémon details "DV/EV" tab: brought up to the style language

Redesigned the DV/EV tab to match the General tab's language (one white grouped panel of zebra-striped rows, connected "combo" controls, no loose buttons or ⋮ menus). The DV/EV toggle is now a segmented [DV | EV] switch, and the old per-kind overflow menu became a connected [Max | Re-Roll | Reset] icon combo (double-up / dice / double-down) that retargets to DVs or EVs by the active mode. Future Shiny dropped its checkbox and ⋮ menu for a segmented [Shiny | Non-Shiny] control plus a dice re-roll button: the selection is reactive — bound to boxData.isShiny, so dragging the DV bars into a (non-)shiny combination flips it too; clicking a segment forces that state, and the dice re-rolls a fresh combination within the current state. New inline SegSel component (a selectable text segment whose active is a data binding, not a checkable toggle, so it never drifts from the underlying value). QML-only; tst_qml_screens + full ctest green, screenshot-verified. VERSION 0.9.1-alpha → 0.10.0-alpha (MINOR — a whole-tab redesign, like the General tab).

2026-06-17 – Pokémon details header: narrow the tabs + species picker so it fits

The redesigned (slimmer) panes left the details header overflowing: the General/DV-EV/Moves tabs stretched edge-to-edge with big gaps, and the species/level/status top bar ran off the narrower right pane. Gave the TabButtons a content width so they sit snug instead of spread, and narrowed the species picker (font*14font*10; Gen 1 names are ≤10 chars). QML-only. VERSION 0.9.0-alpha → 0.9.1-alpha (PATCH).

2026-06-17 – Pokémon details "General" tab: redesign + type-combo display fix

A big iterative redesign of the Pokémon details General tab, capped by a real bug fix. Fixed type combos showing the wrong type (Charizard read as Ghost/Fighting): TypesModel has a "-----" placeholder at row 0, so a type at store index i is at model row i+1, but valToIndex returned i — selecting every type one row early. One-line fix (ret = i + 1); the mon data was always correct (verified by a save-load test). The redesign: per-field actions are now connected segmented "combo" groups (Nickname/Type/OT get [randomize | clear], Nature gets randomize) instead of loose icons / ⋮ menus; rows are grouped into one zebra-striped panel with muted labels (Bag/Market feel); the sprite pane is narrower (~38%); Exp sits between Lv. N / Lv. N+1 markers with a hover value; Catch Rate became a "Catch Difficulty" Easy↔Hard slider (markers above the bar, byte on hover); Type clear resets to the species' DB default via a new PokemonBox::correctTypes() (the multi-bool update() is unreliable from QML). Also fixed a latent GlancePane overlap (the stats had no width, so the sprite overlapped them) by giving the stat groups a real implicitWidth. New regression tests: tst_models (valToIndex row correctness), tst_pokemonbox (correctTypes → Fire/Flying), tst_storage (loaded-mon data). Full ctest green. VERSION 0.8.15-alpha → 0.9.0-alpha (MINOR — a whole-screen redesign, not a small fix).

2026-06-16 – Pokémon details screen: scrollbar-lane fix + consistency / cleanup pass

Brought the Pokémon details editor — one of the last screens carried over from the 2020 build — up to the conventions the later screens established. The General tab's ⋮ overflow menus (Nickname / OT Name / OT ID) no longer sit under the Material scrollbar: the scrollable ColumnLayout now reserves the 16px scrollbar lane (availableWidth - 16), and the Exp slider's one-off rightMargin: 25 was replaced by that shared lane. Added the standard textH/comboH height knobs so the tab's text fields and combos line up at consistent row heights (the self-sizing nickname NameDisplay was left alone). Cleaned up GlancePane — removed a dead commented-out width block and collapsed two identical-branch ternaries on the HP slider's to and track colour to plain calls (behaviour unchanged) — and fixed a "Corect Move" → "Correct Move" typo in the move overflow menu. QML-only; tst_qml_screens green (pokemonDetails clean) and full ctest 66/66. VERSION 0.8.14-alpha → 0.8.15-alpha (PATCH).

2026-06-16 – Item tooltips: real locations + fixes, and wired into the Bag / item picker

Accuracy and reach pass on the item tooltips. Corrected the locations: every TM now names where it's actually obtained — the nine Celadon TM-counter buys, the eight Gym-Leader gifts, the three Celadon Game Corner prizes (Dragon Rage 3,300 / Hyper Beam 5,500 / Substitute 7,700 coins), the Celadon-roof drink-for-TM girl (Ice Beam / Rock Slide / Tri Attack), and the ground finds by route/dungeon (pulled from the map data — maps.json — and the pokered scripts). Fixed the errors Twilight caught: Potion is no longer called the cheapest heal (the vending Fresh Water is cheaper and heals more), the Master Ball no longer claims it "can't be sold," and the PP restoratives / Moon Stone / Exp All got real find spots instead of "in the field." Wired the tooltip beyond the Market: it's on the item picker (SelectItem) now — both the selected combo and each dropdown row — so it appears on the Bag/Items screen and anywhere an item is chosen, tied to the item rather than the screen (ItemSelectModel gained infoForInd / the itemSelectInfo role). Full ctest 66/66. VERSION 0.8.13-alpha → 0.8.14-alpha (PATCH).

2026-06-16 – Item tooltips: descriptions for ALL items + a centered info badge

Completed the per-item tooltip content. Every one of the 152 item entries now has an authored info blurb — what it is and how it's obtained in the US English Red/Blue game: the medicines, balls, stones and vitamins with where they're sold; the key items with who gives them and where; the TMs (move + effect, with the nine Celadon Dept. Store purchases and the eight Gym-Leader gifts named) and the HMs; and the glitch entries explained at the code level (badges / Pokédex / Coin as stray bag items, the unused ITEM_xx slots, the elevator FLOOR_xx markers). Also centered the "i" in the tooltip's title badge (it was sitting low and to the right). Content-only in items.json plus a one-line QML alignment fix; full ctest 66/66. VERSION 0.8.12-alpha → 0.8.13-alpha (PATCH).

2026-06-16 – Detailed item tooltips: data plumbing + a redesigned tooltip (Market, first content)

First slice of the per-item detailed tooltips. Items can now carry an authored info blurb — a new optional field in items.json, surfaced through ItemDBEntry::getInfo. The Market exposes it via a new InfoRole / dataInfo (market entries gained an infoText(); store and player rows return their item's info). A new DetailToolTip component overhauls the help-mode tooltip: a small info badge + a bold title (the item name) over a wrapped body, shown only when the header "?" toggle is on and the row actually has info. It's wired onto the Market list rows. Authored the first 11 entries — the Special items (Nugget, Rare Candy, Max Revive), the Vending-machine drinks, the priced Glitch items (Safari Ball, the unused ITEM_32 "PP Up 2", the Game-Corner Coin — each explained at the code level), and two Normal examples (Potion, Ultra Ball). Remaining items' info, the auto-derived facts (teaches / found-at from the existing cross-refs), and wiring the tooltip into the other item screens come next. Full ctest 66/66. VERSION 0.8.11-alpha → 0.8.12-alpha (PATCH).

2026-06-16 – Accent the brand: "Poke" -> "Poké" everywhere user-visible

Standing rule from Twilight: plain "Poke" is a typo — it must always carry the accent (Poké / Pokémon / Pokédex / Poké Mart / Poké Ball / Poké Doll / Poké Flute), in and out of the app. Swept every user-visible occurrence: the screen titles (router.cpp — Pokédex, Pokémon, Pokémon Details), the Home tiles and the Market venue label (HomeIconsModel, Pokemart.qml → "Poké Mart"), ~20 in-app help tooltips across the Pokémon-details / trainer-card / tileset screens, and the four item display names in items.json (Poké Ball, Poké Doll, Poké Flute, Pokédex). Code identifiers, route ids, QML filenames and the uppercase internal item name keys are deliberately left alone. One data follow-on: maps.json referenced the ground-pickup Poké Ball by its readable name — which is also the link key (MapDBEntrySpriteItem::deepLink resolves the item through the shared name index) — so that reference was updated in lockstep (the mismatch was caught by tst_sprite_data), and tst_bridge's title assertion was updated. The README now also states the editor targets the US English release of Red & Blue. The app's own name ("Pokered Save Editor") was left as-is pending Twilight's call. Full ctest 66/66. VERSION 0.8.10-alpha → 0.8.11-alpha (PATCH).

2026-06-16 – Market: the Sell list hides un-sellable items (keeps free ones)

The Sell view listed every item in the player's Bag/Storage, including ones that can't be sold. It now lists only items with a discernible price — Item::canSell() (i.e. price >= 0). Items with no price at all (Town Map, the HMs, badges, the key items) drop off the sell list instead of sitting there as dead rows. Free items stay sellable: a price-0 item like the Master Ball still counts (you can sell it for nothing) — it just isn't buyable (the buy gate already requires a price > 0, so free items never appear in the Normal/Vending/Special buy groups). Code-only, in buildPlayerItemList. tst_market_model + tst_qml_screens green. VERSION 0.8.9-alpha → 0.8.10-alpha (PATCH).

2026-06-16 – Market: rename Unbuyable -> Special, add a Vending Machine group

Refines the earlier split after a UX pass with Twilight. The store list groups priced items by how the real game sells them, while every priced item stays fully buyable and sellable in the editor (it infers a buy price, a half-value sell price, and a coin/money equivalent):

  • Normal Items — a Poke-Mart shelf sells it in-game (buy + sell everywhere).
  • Vending Machine — the three Celadon-roof drinks (Fresh Water, Soda Pop, Lemonade), bought in-game from the vending machine (pokered data/items/vending_prices.asm), not a Mart — their own group since it's a separate vendor.
  • Special Items (was "Unbuyable Items") — priced, so sellable, but the game never sells it: Nugget, Rare Candy, Max Revive, and every TM that isn't on the Celadon counter.

Items with no price anywhere (pokered prices.asm 0/absent — Master Ball, Moon Stone, the PP restoratives, the key items) are still listed in none of these. Buyability comes from marts.asm + vending_prices.asm, carried as item-index sets in code (no JSON touched). The Game Corner header stays "Inventory". ItemMarketModel only; tst_market_model + tst_qml_screens green. VERSION 0.8.8-alpha → 0.8.9-alpha (PATCH).

2026-06-16 – Market: split "Normal Items" into Normal + Unbuyable, rename Inventory

The Pokemart's catch-all "Normal Items" section is now two sections that match how Gen 1 actually works. Normal Items are the ones a reachable Poke-Mart really stocks — you can buy and sell them. Unbuyable Items are priced (so still sellable) but sold by no mart: Nugget, Rare Candy, Max Revive, the vending-machine drinks, and every TM that isn't on a Celadon shelf. Buyability is taken straight from pokered data/items/marts.asm (the union of every reachable mart's stock — the two unused clerk texts are ignored, since their stock is never purchasable and is sold elsewhere anyway). An item with no price in any currency (price 0 / absent in prices.asm — Master Ball, Moon Stone, the PP restoratives, the key items) is listed in neither section: there is no way to buy or sell it, so it isn't shown. The Game Corner's "Pokemon Inventory" section is renamed "Inventory" and gets the same Normal/Unbuyable split. C++-only in ItemMarketModel (the mart stock list lives in code, no JSON touched); full ctest green (66/66). VERSION 0.8.7-alpha → 0.8.8-alpha (PATCH).

2026-06-16 – Market: defaults to Buy+Pokemart, steadier delta, rename, tidier release notes

Small follow-ups: the Market now opens on Buy + Pokemart (ItemMarketModel::isBuyMode defaults to true). The exchange ±delta superscript no longer shifts the balance number — it's overlaid at the number's top-right (the number's box is sized to itself; the delta is anchored, out of the layout) so the number stays put as the delta appears / changes length. Renamed the Game Corner section "In-House Exclusives" → "Pokemon Inventory". Dropped a clunky explanatory line from the release-notes template (release.yml). QML + a tiny C++ default/string; full ctest green (66/66). VERSION 0.8.6-alpha → 0.8.7-alpha (PATCH).

2026-06-16 – Market: three layout fixes (converter split, delta superscript, pane headers)

Polish on the Market screen: (1) the converter's two sides are now an even 50/50 split (both columns Layout.preferredWidth: 1 + fillWidth; the Money side was wider because its bigger number drove the implicit width). (2) The ±change is now a small superscript at the top-right of each big balance (a Row of [number][tiny delta] with the delta anchored to the number's top) instead of a line floating above. (3) The two shop panes line up again: moving the strips to one full-width header had left the right pane with a tall accent "Cart" bar the left pane lacked — the right header is now a tint section-header (CART ×N) matching the left list's section headers (same height/style). QML-only; tst_qml_screens green. VERSION 0.8.5-alpha → 0.8.6-alpha (PATCH).

2026-06-16 – Exchange: fix the money<->coin RATE + a clear "+Money / +Coins" converter

Fixed the exchange rate. The money exchange was inverted — it gave ~20 coins per ₽1 instead of costing ₽20 per coin. The rate (gameCorner.json price: 20 = ₽20 per coin, the basis for the whole Game Corner/Mart economy) was always right; the C++ used it backwards. ItemMarketEntryMoney now treats the traded unit as one coin (onCart = coins): buying N coins costs buyRate·N money, selling N coins returns sellRate·N (the half-back policy). Added moneyDelta()/coinsDelta(); rewrote onCartLeft/canCheckout/checkout and the model's exchangeMoney/CoinsAfter around them. No JSON changed (data was correct).

Redesigned the converter to be immediately obvious: MONEY on the left, COINS on the right, each with a big live balance, a +/- change above it, and a button right under it — "+ Coins" (buys a coin, near coins) and "+ Money" (sells a coin, near money) — with the per-coin rate under each (₽20 / coin, ₽10 / coin). The two buttons drive one net axis (new exchangeAdjust(±1) / exchangeNet model API; new exchangeBuyRate/exchangeSellRate props); they auto-repeat on hold and disable at the money/coin caps. (Replaces the spend→get lanes.) Tests: exchangeMode_swapsMoneyForCoins (now ₽20/coin)

  • new exchangeAdjust_netAxis. Full ctest green (66/66). VERSION 0.8.4-alpha → 0.8.5-alpha (PATCH).

2026-06-16 – Release notes: auto-describe each deployment from the changelog

Rewrote release.yml's Compose release notes step so a GitHub Release actually describes that deployment instead of pointing users elsewhere. New structure, top→bottom: what the app is → prerelease note → "What's new in this release""How to get it" (downloads) → Links (Pages docs, full changelog, issues), with the auto "What's Changed" commit list appended below. The "What's new" section is pulled from our living changelog automatically: it finds the previous release tag by ancestry (git describe, robust to the version reset) and extracts the entries added to notes/version/ since then (already plain-English). A hand-written notes/releases/<version>.md overrides the prose for a big release. The release job now checks out with fetch-depth: 0 + fetch-tags. CI-only (no app change, no version bump). Existing stray/old release bodies can be backfilled on request.

2026-06-16 – Market: Exchange is now a money<->coins CONVERTER (not a shop list)

Reworked the Exchange experience so it stops feeling bolted onto the shopping cart. The two segmented strips moved to a single full-width header, and the body now switches: Buy/Sell shows the two-pane shop; Exchange shows a focused converter card — both balances (Money ⇄ Coins) shown large with a live resulting balance under each, and the two swap lanes ("₽ → ⭘" and "⭘ → ₽") each with a -/amount/+ stepper and a live "= you get" readout. Checkout still commits. New inline StepPill component (shared by the shop rows and the converter lanes). New model role dataMoneyDir (1 = Money=> Coins, 0 = Coins=>Money) so the lanes label themselves. The old dual-currency receipt variant in the right pane is gone (the converter replaces it). VERSION 0.8.3-alpha → 0.8.4-alpha (PATCH). Full local ctest green (66/66, incl. the empty new-file GUI path).

2026-06-16 – Market: header title "Market", wider cart, + SemVer reset (0.10.1 → 0.8.3)

Two small UI fixes and a version-policy correction. UI: the screen's header title is now "Market" (router.cpp screen registration; the Home tile already was, and the venue tab stays "Pokemart"); the cart pane is a bit wider (0.330.37 of the screen).

SemVer reset (Twilight's call). The MINOR number had been bumped too eagerly (every feature → 0.8→0.9→0.10), running it "way too late". Policy going forward: PATCH is the default for almost everything (the PATCH number is not capped at 9 — let it run to 2-3 digits), and MINOR is reserved for genuine milestones only. The line is reset back to the 0.8 series: VERSION 0.10.1-alpha → 0.8.3-alpha (continuing from the released v0.8.2). The already-published v0.9.0 / v0.10.0 / v0.10.1 pre-releases on GitHub are stray higher numbers (same work, now folded into the 0.8 line) — they can be deleted on request to tidy the release list. Guidance updated in VERSION + reference/versioning.md. Full local ctest green (66/66).

2026-06-15 – Market: rename Home tile, move Exchange into the venue strip, round selected segments

Small Pokemart UI tweaks (Twilight): (1) the Home tile label is now "Market" (the venue tab stays "Pokemart"; HomeIconsModel.qml only). (2) Exchange moved from the action strip to the venue strip: action is now [Buy | Sell] (disabled while Exchange is selected), venue is [Pokemart | Game Corner | Exchange]. (3) Fixed the segmented control's selected fill not following the rounded ends — clip is rectangular, so the end segments' fill now uses per-corner radius (topLeftRadius/… , Qt 6.7+) to match the strip's radius. QML-only; tst_qml_screens green. VERSION 0.10.0-alpha → 0.10.1-alpha (PATCH).

2026-06-15 – Pokemart: one unified Buy+Sell cart per currency (+ fix a cross-app use-after-free)

The Pokemart cart now holds buys and sells together in a single currency. Within a venue (Pokemart = money, Game Corner = coins) you can cart purchases AND sales at once; the Buy/Sell strip only filters the left VIEW, it no longer splits or clears the cart. The receipt itemizes everything with + for sells, - for buys, nets to one signed total, and shows the balance after. Exchange stays its own (separate- currency) mode — money<->coins can't net into a single-currency total.

Model work: ItemMarketEntryStoreItem/PlayerItem no longer mode-gate on the buy flag (compat Either/Either); direction is intrinsic, carried as a plain cartSignVal member (sell +1, buy -1). totalWorth() is now the signed net and moneyLeftover() = currency balance + net. The build creates BOTH sell and buy rows into one list, tagged ViewBuy/ViewSell; a new ItemMarketViewModel (brg.marketViewModel) slices the left list to the active view and re-filters on the Buy/Sell toggle WITHOUT a rebuild (so the cart survives). New roles dataViewTag / dataCartSign. Footer is a single Checkout button.

Use-after-free fix (found via the GUI tests' new-file path). The entry aggregates (totalWorth/canAnyCheckout/totalStackCount) swept the global static instancesCombined/instances registries, which accumulate rows across every model + every per-test app. Building store rows in every mode (this change) plus the per-test app teardown made an aggregate read a freed entry (0xfeeefeee, crash from a QML binding). Fixed by sweeping the current model's own live list via a new ItemMarketEntry::activeList (set by ItemMarketModel::buildList) instead of the cross-app statics. Tests: tst_market_model unifiedCart_buyAndSellNetTogether; the GUI nav/fidelity suites (the empty new-file path) now pass. Full local ctest green (66/66). VERSION 0.9.0-alpha → 0.10.0-alpha (MINOR).

2026-06-15 – Pokemart: segmented mode header + Exchange as its own mode

Replaced the static mode title and the Buy/Sell + Currency footer buttons with two connected, single-select segmented control strips in the left header: action Buy / Sell / Exchange and venue Pokemart / Game Corner (venue disabled in Exchange). The footer is now a single Checkout button (AppFooterBtn1). The segmented control is an inline component SegStrip styled for the accent bar (selected = light fill + accent text; connected, no gaps).

Exchange is now its own mode/list instead of a confusing "Money Exchange" section wedged atop the Game Corner buy/sell lists. Model work:

  • ItemMarketEntryMoney gained a per-row forceDir (DirToCoins / DirToMoney / DirGlobal) + a buying() helper, so a row's swap direction is fixed rather than read from the global buy flag; its compat is now Either/Either (these rows are only built into the Exchange list). Added an exchange-aware canCheckout() that gates on the currency actually spent (the base's single-currency moneyLeftover() is meaningless for a swap).
  • ItemMarketModel gained isExchangeMode + buildExchangeList() (a header + both swap rows). The money-exchange rows were removed from buildPlayerItemList/buildMartItemList (buy/sell lists are pure items now). Added dual-currency totals exchangeMoney/CoinsStart/After that mirror ItemMarketEntryMoney::checkout() exactly, so the receipt preview can never disagree with the commit.
  • The receipt has an Exchange variant: a money + coins before → after (Δ) summary (instead of the single-currency Money-on-hand/Total/Balance), with its own overflow/affordability warning.

Tests: tst_market_model exchangeMode_swapsMoneyForCoins (build = 3 rows; carting Money=>Coins lowers money by the spent amount, raises coins, and checkout applies it); the helper resets exchange mode defensively. Full local ctest green (66/66). VERSION 0.8.2-alpha → 0.9.0-alpha (MINOR — new feature).

2026-06-15 – Pokemart: widen the cart pane to a deterministic 1/3

The Layout.horizontalStretchFactor 5:3 split wasn't landing where intended (the receipt looked ~20% wide). Switched to an explicit width: the receipt pane is now Layout.preferredWidth: paneRow.width * 0.33 (fillWidth: false) and the list takes the rest (~67%) — a deterministic 1/3 cart. VERSION 0.8.1-alpha → 0.8.2-alpha (PATCH).

2026-06-15 – Pokemart shopping list refactored into a proper list (hover/zebra rows + stepper pill)

Made the left shopping list look like a real list instead of centered labels/textboxes/buttons. Each item is now a clean left-aligned row – name | owned (sell) | unit price | an inline -/qty/+ stepper "pill" as the row's action – with a whole-row hover highlight (accent-tinted) and subtle zebra striping, faint separators, and "msg" rows restyled as proper uppercase section headers with a tint bar. The qty field is borderless inside a rounded stepper pill (which turns white on row hover). Dropped the old per-row running cart total (the receipt itemizes + totals it better). Unsellable rows show a muted "Can't sell" in place of the stepper. The receipt pane was narrowed (panes are now 5:3 via Layout.horizontalStretchFactor, giving the list more room). QML-only; tst_qml_screens green (pokemart loads clean). VERSION 0.8.0-alpha → 0.8.1-alpha (PATCH).

2026-06-15 – Pokemart becomes a two-pane shop + receipt (new cart filter model)

Reworked the Pokemart screen from a single scrolling list into two panes: the shopping list on the left (unchanged — the centered -/amount/+ stepper rows, where you build the cart) and a store-style receipt on the right. The receipt itemizes the cart instead of summing it: money on hand, then one buy/sell line per carted item (xQty @ unit and a signed line total), a divider, the Total, the Balance after, and any not-enough-money / no-space warning right by the total. Empty cart shows a "Your cart is empty." placeholder. The floating summary box and the old bottom status bar are gone (folded into the receipt). Footer (Buy/Sell · Checkout · Currency) unchanged.

Backed by a new ItemMarketCartModel (mvc/itemmarketcartmodel.*, brg.marketCartModel) — a QSortFilterProxyModel over ItemMarketModel that keeps only rows with cartCount > 0 and drops the "msg" section headers, inheriting the source role names so the receipt delegate reads the same data* roles. It re-filters live (the market model emits per-row + model-wide dataChanged on every cart edit), so rows enter/leave the receipt as their count crosses zero; the model-wide totals stay on ItemMarketModel. Wired in bridge.{h,cpp} + CMakeLists.txt. Test: tst_market_model cartModel_filtersToCartedRows. Full local ctest green (66/66). VERSION 0.7.6-alpha → 0.8.0-alpha (MINOR — new feature).

2026-06-15 – Add a proper errorColor palette token (Settings) and use it on Pokemart

Did the error red properly instead of a magic literal. Added errorColor to Settings right beside the primary palette (Q_PROPERTY + signal + QColor errorColor = QColor("red")), exposed as brg.settings.errorColor. It's a fixed, theme-independent redsetColorScheme() deliberately leaves it alone so a recoloured palette never turns "error" into the accent (and it's not derived from primaryColor, which is the pink #d81b60). Pokemart's four red spots (moneyColor, the cart-amount field, the two summary-box signs) now read brg.settings.errorColor instead of the literal "red". Look unchanged (still red). Other screens that still use a literal "red" can migrate to this token over time. Full local ctest green (66/66). VERSION 0.7.5-alpha → 0.7.6-alpha (PATCH).

2026-06-15 – Pokemart: revert error color to literal "red" (primaryColor is pink; theming coming)

Follow-up to the Pokemart modernization below: that pass had swapped the error color from the literal "red" to brg.settings.primaryColor. Twilight pointed out primaryColor is pink, not red — and a theming pass is planned, so screens shouldn't bake a palette role in as "the red". Reverted all four spots in Pokemart.qml (moneyColor, the cart-amount field, and the two summary-box signs) back to the literal "red". VERSION 0.7.4-alpha → 0.7.5-alpha (PATCH).

2026-06-15 – Modernize the Pokemart screen (clean rebuild + fix the stuck Checkout button)

First modernization pass on the Pokemart/Game-Corner shop screen — one of the oldest, buggiest, half-finished screens. Look and behavior are unchanged; the rebuild is internal only. Pokemart.qml delegate was rebuilt off auto-layouts: the fragile Rectangle { width: 1; height: 50 } row frame and its sibling-anchor chain became a clean centered cart stepper with the name/price/owned-count anchored to its left and the running cost to its right. Stripped the pre-2026 cruft: dead getTo() code, the unused curName(), the never-true === "phony" ternary branches, a duplicated useSigning check in moneyStr, the four mode-toggled header Texts (now one headerText()), the four manually-juggled footer status/error Texts (now one statusText() with explicit priority). The error color stays the literal "red" — deliberately not primaryColor (which is pink, and theming is coming, so screens shouldn't bake in a palette role for a plain red). The per-delegate isLast breathing-room hack became a ListView.footer. Fixed the long-noted stuck-hover Checkout button at its root in FooterButton.qml: a footer button disabled while hovered kept hovered == true (Qt stops sending hover-leave to a disabled item) and stayed highlighted — hoverEnabled: enabled forces it false the instant it disables. VERSION bumped 0.7.3-alpha → 0.7.4-alpha (PATCH). Green: tst_qml_screens (pokemart loads clean), tst_market_model, tst_bridge.

2026-06-15 – Stop auto-generating screenshot GIFs (still PNGs only; GIFs added manually)

Per Twilight, the screenshot pipeline no longer auto-generates animated GIFs — those will be added manually, one at a time. Removed the three frame-sequence capture routines (tileset_anim, typing, tab_cycle) from screenshooter.cpp; the capture scripts (capture_screenshots.{ps1,sh}) and CI (pages.yml, release.yml) no longer install Pillow or auto-assemble GIFs, and Pages no longer copies *.gif. The tool now produces flat screens/*.png + editor/*.png only. scripts/make_gifs.py (the Pillow assembler) is kept for manual GIF assembly, and Pillow stays credited (note reworded to reflect manual use). Notes updated (screenshots.md, deployment.md, CLAUDE.md). Tooling/CI + a small Credits-note change — no app-logic or save-format change.

2026-06-15 – Fix README blockquote on Pages: upgrade CI Doxygen to 1.17 (+ single-line blockquote)

The README's intro blockquote rendered wrong as the Doxygen home page: no italics (literal underscores) and a **leaked literal </blockquote>** that the following --- turned into a stray <h1> (also polluting the nav/auto-TOC). Root cause: CI used ubuntu's Doxygen 1.9.1, which has these Markdown bugs; the local toolchain is 1.17.0, which renders fine — so a local doxygen test misleadingly passed while Pages stayed broken. Fix: install Doxygen 1.17.0 from the official binary in CI (both pages.yml and the release docs job), replacing apt's 1.9.1, so CI matches local. Also hardened the source — the intro blockquote is now single-line with *...* emphasis (renders on 1.9.1 and 1.17 and on GitHub alike). Doxygen-markdown gotcha noted in reference/documentation.md.

2026-06-15 – GitHub Pages site (docs + screenshots); release-notes + release-policy standards

.github/workflows/pages.yml deploys ONE GitHub Pages site on every push to main (not a release, not the git repo): the Doxygen docs home is the root (…github.io/pokered-save-editor-2/) and the UI images live at /screenshots/<name> (+ a gallery). So the docs are browsable online and the README can embed always-current images, with zero repo-size growth and no third party. The docs main page is the README (USE_MDFILE_AS_MAINPAGE, untouched); Screenshots + GitHub are added as custom Doxygen top-nav tabs by generating DoxygenLayout.xml (doxygen -l), injecting two <tab type="user"> entries, and building with that layout. It captures headless (screenshooter under xvfb; screens/*.png

  • editor/*.png + GIFs, excluding frames/), runs doxygen, and deploys via configure-pages/upload-pages-artifact/deploy-pages. Docs reference screenshots by the absolute Pages URL (works on Pages, GitHub, and the README alike). The README's own screenshot embedding is left to Twilight (the Pages URLs are ready to use). (Rejected for images: a rolling images-only release — violates "releases are software-only"; an orphan branch — bloats the repo object store; Imgur — purges images / deprecated API / needs a secret. Replaced the interim screenshots.yml.) Also: every GitHub Release now gets a well-structured title + description by default (release.yml composes a downloads table + prerelease/unsigned note, with the auto "What's Changed" appended), and Pillow is pip-installed for the active python3 so the GIFs make it into the screenshots zip. Standing policy recorded in CLAUDE.md + reference/deployment.md: never release anything that isn't a software release / never an images-only release, and release notes are always well-written. VERSION unchanged (CI/deploy infra).

2026-06-15 – Release pipeline green: first release v0.7.2-alpha published

The release pipeline now works end-to-end — v0.7.2-alpha is published with all six artifacts (Windows portable zip + Inno installer, Linux AppImage + tar.gz, docs zip, screenshots zip). Linux / docs / version passed first try; the shakeout was all on Windows + one script path:

  • windeployqt --compiler-runtime is MSVC/g++ only → dropped it; copy libc++/libunwind/libwinpthread from the compiler bin by hand.
  • windeployqt invoked by full path ($QT_ROOT_DIR/bin/windeployqt.exe) — a stray windeployqt on PATH hit "Unable to find the platform plugin" and deployed nothing; plus a manual Qt-DLL/QML/plugin fallback + a Qt6Core.dll / platforms/qwindows.dll assertion.
  • Inno Setup ISCC.exe path used ${Env:ProgramFiles(x86)} (braces required — $Env:ProgramFiles(x86) mis-parses); Inno is pre-installed on windows-latest.
  • capture_screenshots.sh finds the screenshooter binary under build/tests/ on Linux (build root only on Windows). Screenshots render on CI via xvfb + llvmpipe (MultiEffect included).

Also wired GitHub into the default workflow (CLAUDE.md): the remote tests CI must be green before FF main (not just local ctest), the release run is watched after, and the issue tracker + PRs are checked as part of prepping main for shipment (event-based, no scheduled ping) with a "now or later?" prompt — never auto-acting. VERSION unchanged (CI/deploy infra).

2026-06-15 – Add the GitHub Actions release/deployment pipeline

Added .github/workflows/release.yml to build and publish release artifacts (the deploy half; tests.yml stays test-only). It triggers on push to main and releases only when the tag v<VERSION> doesn't exist yet (i.e. VERSION was bumped since the last release; -alpha/-beta/-rc → prerelease), with a workflow_dispatch dry-run mode. Each release attaches: Windows portable .zip + Inno Setup installer .exe, Linux .AppImage + portable .tar.gz, Doxygen docs .zip, and a UI screenshots/GIFs .zip (the screenshooter under xvfb). Toolchain mirrors tests.yml (Qt 6.8.3 install-qt-action; llvm-mingw on Windows, gcc on Linux), built Release. New files packaging/windows/installer.iss + packaging/linux/PokeredSaveEditor.desktop; new doc notes/reference/deployment.md; Inno Setup + linuxdeploy credited. CI/deploy infra — VERSION unchanged. Not yet exercised on GitHub (first-run shakeout expected, like tests.yml).

2026-06-15 – Screenshot tool: capture at a fixed 750×480 (the UI's small-rectangle size)

The screenshots kept looking "too big" because they were captured at 1130×740 — but that's only the fresh-profile default; the app is designed for a small rectangle (its own saved window is ~751×480). The tool now captures at a fixed 750×480 (rounded), overridable with PSE_SHOT_SIZE="WxH", and resizes before start() so the QML lays out once at the final size (a late resize had left Home's greyed Maps/Options tiles unrendered). Shots now match the app's actual window. Tooling only. See notes/reference/screenshots.md.

2026-06-15 – Screenshot tool: real GPU window for effects, overlay/popup centering, hover, CI via xvfb

Follow-up fixes after review. The offscreen platform (software AND default-RHI, both tested) drops all MultiEffect/layered content (Credits cards, Home's greyed disabled tiles), which made screens look washed-out/"wrong size"; only a real GPU window renders them, so the tool now runs on the native platform and shows the view frameless/Qt::Tool off-screen (no desktop flash) — and capture_screenshots.sh runs under xvfb-run so CI still renders effects headlessly (offscreen+software is the last-resort fallback). Fixed the quick-edit popup rendering bottom-right: a plain QQuickView leaves QQuickOverlay at size 0×0, so anchors.centerIn: Overlay.overlay popups don't center — fixOverlay() sizes the overlay to the window. HiDPI grabs are downsampled to the logical 1130×740. The keyboard hover now hovers a real glyph pill (so the TilePreview tooltip shows). Removed the Pokédex hover shot (not needed). Tooling only. See notes/reference/screenshots.md.

2026-06-15 – Screenshot tool: render via a real GPU window (fixes missing content) + HiDPI/typing/View All

Screenshots were missing MultiEffect/layered content (Credits showed only its header+background, Home was missing its greyed disabled tiles) and looked the wrong size — because the offscreen + QT_QUICK_BACKEND=software path silently drops those items. The tool now renders through a real GPU-backed window shown frameless/Qt::Tool/off-screen (so it draws exactly like the app's QQuickWidget without flashing on the desktop); the .ps1 no longer forces offscreen (kept as the CI fallback). HiDPI grabs are downsampled to the logical 1130×740 (a 150% display was yielding 1695×1110; QT_SCALE_FACTOR doesn't override screen DPR). The typing GIF now drives the popup's name field (found by its "Enter a name" placeholder, not the tileset combo) so the textbox owns the value and the preview follows. Bag's View All is opened by clicking the real footer button (the old shown- property poke matched the wrong item on Bag). Tooling only; no app change. See notes/reference/screenshots.md.

2026-06-15 – Fix the screenshot pipeline's GIFs (they weren't animating)

The capture pipeline's GIFs didn't animate. Fixes (tooling only, no app change): the static name_anim sequence is replaced by tileset_anim, which drives the full keyboard's TilesetDisplay curFrame 0–7 over an Overworld/outdoor tileset (a plain name preview's frames are byte-identical — only tileset water/flower tiles move); the typing sequence now drives the name editor's field text + str per step so the live GB-font preview builds up letter-by-letter (synthesized key events never reached the modal popup field); make_gifs.py playback durations were slowed (tab cycle 260 → 850 ms etc.); and the tool now wipes its output dir each run so renamed sequences leave no stale files. Re-captured at the new 1130×740 default (the harness already drives that size). See notes/reference/screenshots.md.

2026-06-15 – UI polish: rival box height, View All tooltip, default window size

Three small UI/UX tweaks. (1) The Rival screen's grey card was 360×300 while the Trainer Card's was 500×250; the rival card now uses height 250 to match the Trainer Card (width unchanged at 360, per Twilight: match the height only, rival only). (2) In the Pokémon storage View All drawer, the per-count hover tooltip used the default top-left popup placement and floated away from the number — it now anchors centered under the hovered count (x: (parent.width - width) / 2, y: parent.height + 4). (3) The default window size is now 1130×740 instead of 640×480: the first-run fallback in MainWindow::loadState() and the mainwindow.ui initial geometry, plus the two test-harness sizes (tests/helpers/guiapp.h, tests/qml/tst_qml_screens.cpp) that also drive the screenshooter — was 1024×768. Full ctest green (66/66). PATCH bump.

2026-06-15 – Headless UI screenshot + animation-capture pipeline

Added an automated, headless way to capture UI screenshots and animated GIFs of the app — no manual grabbing, no GPU, no real window, and it never touches save data. A new C++ tool projects/tests/tools/screenshooter.cpp (CMake target screenshooter, not a CTest test) boots the real UI offscreen on the shared GUI harness, loads BaseSAV.sav, and grabs every top-level screen, the Pokémon/Bag "View All" drawers, the three Pokémon-editor tabs, both text-editor modes + the keyboard tileset, hover states, and animation frame sequences — via QQuickWindow::grabWindow(). scripts/make_gifs.py (Pillow) assembles the frame folders into GIFs; scripts/capture_screenshots.ps1 / .sh build + run + assemble, writing to tmp/screenshots/ (already git-ignored). Two offscreen gotchas handled: QT_QPA_FONTDIR is set so UI text renders (not tofu), and QT_QUICK_BACKEND=software makes grabWindow() produce real pixels with no GPU (CI-friendly). Wired into the Default Workflow to run by default after a fast-forward of main. Pillow credited (Tools Used). Tooling/test only — no app-code change, so VERSION is unchanged. See notes/reference/screenshots.md.

2026-06-14 – README: polish Twilight's amended draft

Polished a rough round of Twilight's edits to the README into clean prose without changing their intent. Tightened the new tagline ("A Pokémon Red & Blue save editor written in C++/Qt/QML") and intro, simplified the reboot blockquote to "rebuilt from scratch in Qt/C++", fixed a status-section typo, and reworked the convictions list – the new Beautiful UI/UX conviction, plus reworded Graceful failure and No longer a web app entries. Rewrote the Assisted custom-code execution feature bullet and the Synthetic Natural randomization vision from first-person notes into readme prose. Build/test/contributing/architecture sections unchanged.

2026-06-14 – Add assets/references/ for reference material

Added assets/references/ as the official home for reference material used while working on the project – project-folder references and source clones like the pret/pokered disassembly or the GitHub sources credited in credits.json. The folder is tracked via a .gitignore that ignores its contents (* but keeps !.gitignore), so the material stays local-only and restorable while the folder itself lives in the repo – the same "tracked folder, ignored contents" pattern as assets/staging/. Nothing here is a build input. (First entry written under the new inline-changelog policy: it ships in the same commit as the change, with no hash marker.)

2026-06-14 – Shorten notes changelog name to version

b0cd23a - Twilight

With the changelog now living under notes/, the version-info name was redundant. Renamed notes/version-info.md to notes/version.md and the folder likewise, updating every cross-reference and relative link. As a subdirectory, notes/version/ no longer collides with the root VERSION file (the original repo-root version/ collision is why it was once renamed away). VERSION untouched.

2026-06-14 – Move the changelog into notes/

199eb7e - Twilight

Relocated the changelog (version-notes.md + version-notes/) from the repo root into the notes/ tree as version-info, fixing all cross-links and dropping the now-redundant explicit Doxyfile INPUT lines (the recursive notes/ entry already covers them). Historical mentions of the earlier version/ to version-notes/ rename were kept and annotated. VERSION unchanged.

2026-06-14 – De-name the notes; neutral, shared-project tone

6bc16e5 - Twilight

Swept the notes for personal/maintainer name references and gendered pronouns, moving to a neutral, professional, shared-project tone.

2026-06-13 – README: UI image + project status

6811597 - Twilight

Rearranged the UI/UX progress image and refreshed the project-status text in the README.

2026-06-13 – README polish

61a9f4e - Twilight

Fixed a doubled word, tidied grammar, and removed a dead Screenshots table-of-contents link.

2026-06-13 – De-glorify the docs; state the goal; archive the 2020 README

aacf00d - Twilight

Toned down promotional language across the docs, stated the project's actual goal plainly, and archived the original 2020 README as a historical artifact.

2026-06-13 – Rewrite the README

96fbb92 - Twilight

Full README rewrite covering status, features, build/test instructions, contributing, and the randomization modes.

2026-06-13 – Add a tracked-but-ignored tmp/ scratch folder

286eb47 - Twilight

Added a tmp/ scratch folder for build/run artifacts – tracked as a folder but with its contents gitignored.

2026-06-13 – Rename assets/icons staging folder to assets/staging

6eeba9c - Twilight

The repo-root icons folder is just a gitignored staging area for importing art (distinct from the app icon tree), so it was renamed assets/staging to match its purpose. Notes updated; no build inputs affected.

2026-06-13 – Reorganise save fixtures into assets/saves/

7357782 - Twilight

Reorganised the test save fixtures under assets/saves/ (natural-clean, synthetic-clean, synthetic-dirty) and moved the structure template in, adding a human-readable structure.md wired into Doxygen. All fixture-relative test paths and READMEs updated; full suite green (66/66).

2026-06-13 – Stop tracking Qt Creator's CMakeLists.txt.user

8e6598a - Twilight

Stopped tracking Qt Creator's per-user CMakeLists.txt.user and gitignored it.

2026-06-13 – Note the Windows VERSION checkout gotcha

2652422 - Twilight

Documented the Windows case-insensitivity gotcha where checking out old history collides with the VERSION file.

2026-06-13 – Rename to bare VERSION + version-notes/

dab0a1d - Twilight

Renamed the changelog folder version/ to version-notes/ to clear the case-insensitive collision that had forced the .txt suffix, freeing the bare name VERSION for the version file. Updated CMake, the Doxyfile INPUT, the VERSION header comment, and all cross-links; reconfigure confirmed the version still reads 0.7.0-alpha.

2026-06-13 – Correct the i18n note; defer language switching

bb56fa7 - Twilight

Corrected the i18n note – lupdate works fine; the apparent hang was a UAC prompt – and deferred runtime language switching until a second locale and an Options screen exist.

2026-06-13 – Record the i18n pipeline in the notes

28083c5 - Twilight

Documented the new i18n pipeline across reference/i18n.md, the decisions, status, next-steps, and the notes index.

2026-06-13 – Qt Linguist i18n pipeline + wrapped UI strings

a375363 - Twilight

Stood up a Qt Linguist translation pipeline: qt_add_translations producing pse_en.ts to .qm at :/i18n, a QTranslator installed early in boot (honoring the ui/language setting, else system, English fallback), ~139 QML display literals wrapped in qsTr(), router screen titles via QT_TRANSLATE_NOOP, and a few C++ model strings in tr(). UI chrome only – game-data names are out of scope.

2026-06-13 – SemVer version system with a single source of truth

de30af9 - Twilight

Introduced a SemVer version system whose single source of truth is the repo-root VERSION.txt. CMake reads it, feeds project(VERSION), and generates pse_version.h with the git commit appended as build metadata; boot sets the runtime version from it (no more hardcoded v1.0.0), About shows the cleaned SemVer, and a Windows VERSIONINFO resource embeds it in the .exe. Starting number 0.7.0-alpha; full suite green (66/66).

2026-06-13 – Credit Docker (Tools Used)

bd88c0c - Twilight

Living-credits update – added Docker (now powering the Linux build/test env) under Tools Used.

2026-06-13 – Linux Docker build/test environment

a597ad0 - Twilight

Added a containerised Qt 6.11 + clang Linux toolchain under docker/ that rsyncs the repo into a persistent ext4 volume (ccache-cached) and runs the suite four ways via dtest.ps1: standard offscreen, ASan+UBSan (which are broken on the Windows kit), real-X xvfb, and llvm-cov coverage. First run all green – 66/66 each, ASan clean, 89.73% line coverage.

2026-06-13 – Fix heap-use-after-free in the item market

5bcd3e4 - Twilight

Fixed a heap-use-after-free: totalWorth() walked the shared static registry calling _itemWorth() on entries whose Item could already be freed (box rebuild/teardown). Windows read stale-valid memory; only ASan in CI caught it. Switched to QPointer with guards so stale entries return a safe default.

2026-06-13 – Byte-fidelity test of the Pokemon editor

af4c6d6 - Twilight

Extended tst_gui_fidelity to instantiate the full Pokemon editor over a real party mon and browse it non-destructively – every tab, dropdown, and field – then assert the flattened save is byte-identical. Covers 9 tabs, 9 dropdowns, 22 fields.

2026-06-13 – E2E test of PC-box drag persistence

fd82672 - Twilight

tst_gui_drag now also drives the PC-box reorder/delete on a runtime-populated box and verifies the changes survive a save then reopen.

2026-06-13 – Fire shortcut verbs through a shared action map

b5172ce - Twilight

Extracted the shortcut-to-verb wiring into a shared pse::shortcutActions() used by both MainWindow and the test; tst_shortcuts now asserts every shortcut has an action and actually fires the safe non-dialog verbs.

2026-06-13 – Notes: shortcut/drag tests + otherShortcuts fix

4e35853 - Twilight

Notes for the new shortcut and drag E2E tests, plus recording the otherShortcuts copy-bug fix.

2026-06-13 – Shortcut-binding guard + items drag/drop E2E

7a852ee - Twilight

tst_shortcuts pins every key sequence and guards against collisions; tst_gui_drag drives item reorder/transfer/delete through the live bridge and asserts persistence across a save then reopen.

2026-06-13 – Share the shortcut key map; fix empty otherShortcuts

9d30509 - Twilight

Moved the global shortcut key sequences into boot/shortcutdefs.h so tests can pin them, and fixed an auto os = otherShortcuts copy bug that had left the member empty (the shortcuts only survived via their QObject parent).

2026-06-13 – Drop check-CI-by-default; keep the flake record

d9b3dbc - Twilight

Dropped the short-lived "check CI by default" guidance while keeping the record of the Qt-download flake fix.

2026-06-13 – Note the CI Qt-download flake mitigation

34a1153 - Twilight

Recorded the CI Qt-download flake mitigation (and, briefly, a check-CI-by-default note).

2026-06-13 – Cache Qt + pin 6.8.3 to fix flaky CI downloads

0fe0913 - Twilight

The ASan CI job kept failing at Install Qt when aqtinstall couldn't reach the mirrors. Enabled the install-qt-action cache and pinned the exact Qt version for a stable cache key so a good download is reused.

2026-06-13 – Notes: synthetic fixtures, badgeCount, per-control roadmap

ad61b19 - Twilight

Documented the synthetic-fixture work and the badgeCount fix, and laid out the remaining per-control testing roadmap.

2026-06-13 – Notes: badgeCount fix + synthetic fixtures

557a907 - Twilight

Notes capturing the badgeCount stub fix and the synthetic fixture matrix.

2026-06-13 – Synthetic fixture matrix

03e281c - Twilight

Added a generator that builds deterministic edge-case saves (maxed/zeroed/all-badges/midgame) from a fresh new file via the engine into assets/synthetic/, with a suite asserting each loads, round-trips byte-stable, and carries its edited values; the fidelity test also browses the maxed save. Surfaced the badgeCount stub.

2026-06-13 – Fix badgeCount() to count set badges

3f25da8 - Twilight

PlayerBasics::badgeCount() had been returning the max unconditionally (a 0-badge save reported 8); it now counts the set badge flags per its contract. Found by the synthetic fixtures.

2026-06-13 – Notes: comprehensive testing pass

5e413e6 - Twilight

Notes recording the comprehensive testing pass (fidelity, dirty fixtures, editor verification).

2026-06-13 – Verify the editor with a real selection

79af2b2 - Twilight

tst_qml_screens now injects a real party mon before completeCreate so the Pokemon editor's runtime bindings resolve against real data and it's held to the full zero-warning bar.

2026-06-13 – Notes: corrupt-save crash fix + dirty fixtures

19634c9 - Twilight

Notes for the corrupt-save crash fix and the new dirty-fixture suite.

2026-06-13 – Dirty/malformed save fixtures + negative suite

3aacb24 - Twilight

Added assets/dirty/ (empty/truncated/oversized/all-zeros/all-FF/garbage) and a negative suite asserting wrong-size files are rejected cleanly, right-size garbage loads without crashing, and bad checksums still load. Caught the corrupt-save crash fixed alongside.

2026-06-13 – Clamp out-of-range current-box index on load

bbb18d9 - Twilight

Storage::load() indexed boxes[] (0-11) with the raw current-box byte (0-127), and a malformed all-0xFF save crashed via a null deref. It now clamps an out-of-range index to 0 – a no-op for valid saves (byte fidelity intact) and a graceful default for garbage. Found by the dirty fixtures.

2026-06-13 – Note tst_gui_fidelity in the testing plan

e8f1129 - Twilight

Added tst_gui_fidelity to the testing plan.

2026-06-13 – Byte-fidelity "browsing changes nothing" GUI test

9d9db03 - Twilight

New tst_gui_fidelity: baseline a save, navigate every screen, open/close every modal and dropdown, focus/blur every field without typing, then flatten+recalc and assert the bytes are identical (reporting any changed offsets) – across both progressed and new saves.

2026-06-13 – Notes: GUI suite green; Pokemart fix + harness gotchas

1498fd0 - Twilight

Notes recording the GUI suite green on the kit, the Pokemart crash fix, and the test-harness gotchas.

2026-06-13 – Comprehensive GUI suite green on the kit

91dabef - Twilight

A real-app headless GUI suite on the guiapp harness – navigation sweep, save/load-through-screens with independence and byte-stability, and synthesized-keystroke input – plus the load smoke test, all green (61/61). Includes a batch of harness triage fixes (StackView matching/waits, an allowlisted offscreen-font warning, objectName-located fields).

2026-06-13 – Guard the Pokemart empty-cart crash

d5950d9 - Twilight

The Pokemart footer bindings evaluated during the screen push before the list was built, hitting an empty list and a fatal assert. Fixed by building the list in the constructor (valid from construction, independent of nav-slot order) and returning sane empties from the cart accessors. Found by the navigation test.

2026-06-13 – Clarify in CLAUDE.md that PowerShell can build/test/run/git

256cca3 - Twilight

Clarified in CLAUDE.md that the PowerShell terminal has real access to build, test, run, and git on the Windows machine – it is not limited to the sandbox.

2026-06-13 – Fix the Credits screen failing to open

b21a55b - Twilight

The Credits/About screen never opened due to two QML bugs: a contentWidth property on the Page root collided with a FINAL Control property (renamed to colWidth), and a Page id of top collided with the top anchor inside delegates, breaking icons/links (renamed to root). Verified on-screen; both added to fix-patterns.

2026-06-13 – Redesign Credits/About + data-driven back end

f648391 - Twilight

Reworked credits.json into an ordered sections shape (adding a credit or section is now a pure JSON edit), replaced the eight hardcoded blocks in CreditDBEntry::process() with a single data-driven loop, made CreditsModel section-grouped, and redesigned About.qml with translucent section cards over the wallpaper, colourised icons, clickable links, and a version/copyright footer. Full suite green (57/57).

2026-06-13 – Credit ChatGPT for the rival artwork

791e063 - Twilight

Credited ChatGPT for the rival artwork in both the AI Assistance and Icons sections.

2026-06-13 – Record the rival artwork swap

a502364 - Twilight

Logged the rival artwork swap in status.md.

2026-06-13 – Use the new colored rival.png

0a2aff1 - Twilight

Imported the new colored rival.png into the app asset tree and repointed the Rival screen from the old grayscale art (mirrors the trainer.png swap).

2026-06-13 – Record the Rival screen cleanup

29bb763 - Twilight

Logged the Rival screen cleanup in status.md.

2026-06-13 – Clean up the Rival screen to match the Trainer Card

719f8b1 - Twilight

Replaced the Rival screen's magic-margin positioning with a centred bordered card matching the Trainer Card style (shared height knob, divider under the name), kept the simple name/image/starter stack and identical bindings, and routed access through a null-guarded rival() helper.

2026-06-13 – Soften the Unformat warning copy

e606b67 - Twilight

Softened the Unformat warning – the data is effectively gone unless recovered before an editor or the game destroys it.

2026-06-13 – Source-verified box format/recovery findings

9757368 - Twilight

Recorded source-verified Gen 1 box format/recovery findings cross-checked against the pret/pokered disassembly.

2026-06-13 – Render species markup in View All tooltips

e731288 - Twilight

View All tooltips now render species name markup (e.g. Nidoran with a male sign).

2026-06-13 – Box-format triggers + recovery-opportunity theory

03ae2c7 - Twilight

Notes on the Gen 1 box-format triggers (box-switch / new-file only) and the recovery-opportunity theory.

2026-06-13 – Correct the Unformat warning (erased on box switch)

6f810f3 - Twilight

Corrected the Unformat warning – the data is erased on an in-game box switch, not on open.

2026-06-12 – Lighten Format copy; stress Unformat danger

fe58bb2 - Twilight

Lightened the Format-boxes copy (it just unlocks) while stressing the real data danger on Unformat.

2026-06-12 – Polish the Format-boxes confirm paragraph

c154192 - Twilight

Polished the Format-boxes confirmation copy to reflect that the state depends on how the save was loaded.

2026-06-12 – Reword the Format-boxes confirm for clarity

bd3ad00 - Twilight

Reworded the Format-boxes confirmation middle paragraph for clarity.

2026-06-12 – Clarify the Boxes Formatted warnings (recovery exception)

8dc1ff9 - Twilight

Rewrote the format/unformat confirm copy to match how Storage actually behaves – within a loaded session unformatting is fully reversible by re-formatting; loss only becomes real once the save is reloaded or the game overwrites the freed space.

2026-06-12 – Storage Tools menu + Boxes Formatted warning

5cf12c1 - Twilight

Turned the footer "Boxes Setup" button into a Tools (wrench) menu with a "Boxes Formatted: On/Off" toggle that opens a direction-aware confirm (format = erase+format all but the current box; unformat = soft delete with permanent-loss risk), flipping only the boxesFormatted bit. Also made the storage grid render species gender markup generically.

2026-06-12 – Species markup on the storage grid; unbold View All headers

b2d69a6 - Twilight

Applied the Pokedex name-fix on the storage selection grid so the gender markers show as symbols, and removed the bold on the View All box-number column headers.

2026-06-12 – View All sort icons + condensed columns

2938f53 - Twilight

The View All header sort button now shows the current order's icon (using three PNGs, aspect-fit so the non-square art isn't squished), and the table was condensed roughly in half via per-column widths so it fits without sideways scroll in the common case.

2026-06-12 – Polish Pokemon View All

fe77289 - Twilight

Polished the Pokemon View All overview – zebra row/column tints with whole-row hover, a wider species column with the Pokedex name-fix, a header sort button cycling Dex/Alphabetical/Internal, and a tooltip that appears only when something is traded (an all-caught no-nickname cell has none). Test extended accordingly.

2026-06-12 – Pokemon storage View All overview drawer

74bb2bf - Twilight

Added a Party + non-empty-boxes overview table (rows alphabetised by species), each cell showing the per-box count with a hover tooltip of differing nicknames and a caught/traded split, backed by a new read-only PokemonOverviewModel with precomputed tooltips and wired through the bridge.

2026-06-12 – Credit ChatGPT for badge images + leader portraits

42ed2cd - Twilight

Credited ChatGPT for the gym-badge images and gym leader portraits, and marked the trainer-card badge/portrait work approved.

2026-06-12 – Normalise badge icons to 256x256 square canvases

64797bc - Twilight

Re-processed the badge icons onto uniform 256x256 centred square canvases (content at ~98%) so earned badges and unearned shadows render at a consistent footprint. No QML change.

2026-06-12 – Recrop gym-leader shadows to square busts

2af7159 - Twilight

Recropped the tall full-body leader silhouettes into square head-and-shoulders busts so they fill the badge cell uniformly with the near-square badge icons.

2026-06-12 – Aspect-fit + center badge grid images

efdf3b5 - Twilight

Switched the badge-grid delegate from Stretch to PreserveAspectFit (with mipmap and a capped sourceSize) so the non-square art isn't distorted, and re-imported the eight badge icons after size optimisation (~1MB to ~360-430KB each).

2026-06-12 – Badge grid: icons (earned) + leader shadows (unearned)

cdbda00 - Twilight

The Trainer Card badge grid now shows the badge icon when earned and the gym leader's shadow when unearned (replacing the old on/off pair and the opacity dimming, since the shadow conveys state). Imported the artwork and swapped the qrc entries.

2026-06-11 – Update trainer-card artwork (revised trainer.png)

55f0e37 - Twilight

Updated the Trainer Card front to the revised trainer.png artwork.

2026-06-10 – Swap trainer-card artwork to colored trainer.png

579e948 - Twilight

Replaced the grayscale Gen-1 sprite on the Trainer Card front with the new colored two-trainer illustration; layout unchanged.

2026-06-10 – Correct status note (View All is a hand-rolled panel)

d333449 - Twilight

Corrected a status note to reflect that View All is a hand-rolled slide panel, not a Material Drawer.

2026-06-10 – Block hover pass-through; narrow the View All panel

586695d - Twilight

Stopped the bag rows' hover delete-chip lighting up through the open View All panel by adding a blocking HoverHandler to the panel and scrim, and narrowed the panel slightly.

2026-06-10 – View All panel: drop border, block scroll/click pass-through

7a0027a - Twilight

Removed the panel's right-edge divider (it read as a grey border) and stopped leftover wheel/clicks from falling through to the panes behind by adding a full-size MouseArea + WheelHandler to the panel and scrim.

2026-06-10 – Replace the View All Drawer with a hand-rolled panel

54a8468 - Twilight

The Material Drawer kept leaving a white strip and frame that padding/inset tweaks couldn't fix, so it was replaced with a plain Rectangle we fully control – x-animated slide, fading scrim that closes on outside click, flush header, no frame – keeping the same overview table and behaviour.

2026-06-10 – Try to make the View All drawer full-bleed

251a26f - Twilight

Attempted to make the Drawer full-bleed by zeroing all insets and elevation and giving it a flat background (later superseded by the hand-rolled panel).

2026-06-10 – Remove the white strip above the drawer header

23ff6a2 - Twilight

Set the Drawer content padding to 0 to remove the white strip above the accent header.

2026-06-10 – Narrow the View All drawer

9f26d18 - Twilight

Capped the drawer width so the fillWidth Item column stopped eating the slack.

2026-06-10 – "View All" items overview drawer on the Bag screen

a71853b - Twilight

Added a left-edge slide-in drawer (new leftmost footer button) showing a condensed, alphabetised table of every item the save holds – Item / Bag / Storage – backed by a new read-only ItemOverviewModel that aggregates both boxes by index (so glitch items still appear) and is wired through the bridge. Test added; full suite green (57/57).

2026-06-10 – Checked items show the delete chip in its lit state

9831f66 - Twilight

A checked item row now renders the delete chip in its filled red/white-X "armed" look permanently, driven by a lit = hovered || checked condition.

2026-06-10 – Reserve the delete-chip slot to stop row reflow

76c5be7 - Twilight

The delete chip toggled with visible:, collapsing its layout slot and reflowing the whole row on hover; it's now permanently in the layout and just fades opacity, so nothing resizes.

2026-06-10 – Delete chip transparent at rest; clear of the scrollbar

84c1c68 - Twilight

Made the per-row delete chip transparent at rest, and fixed the recurring "button under the scrollbar" problem by reserving the scrollbar lane and letting the item combo shrink so the trailing chip stays clickable. Documented the list/grid variant in ui-patterns.

2026-06-10 – Never lose items on stack overflow; cross-pane owned total

d4a753c - Twilight

Item transfers no longer clamp a stack to 99 and drop the excess – overflow becomes its own second row, or the transfer is refused if there's no room (no silent loss, ever) – and the item dropdown now shows each item's total owned across both panes. New tests; full suite green (57/57).

2026-06-10 – Auto-stack item transfers + grey out duplicate picks

d9ad035 - Twilight

Transfers now auto-stack onto an existing matching row (clamped to 99) instead of inserting a duplicate, and the item dropdown greys out names already present in the same pane. Pre-existing duplicate save data is deliberately left untouched. New tests; suite green (57/57).

2026-06-10 – Drag-and-drop reorder + cross-pane transfer on the items list

07fbeda - Twilight

Brought the storage grid's drag interaction to the Bag/PC items list – rows are DropAreas, the content floats to an overlay while dragging, drag starts from a left grip handle (controls keep their input), and you can reorder within a list or transfer bag-PC. Removed the bulk-action footer in favour of a per-row delete chip. Regression tests added; suite green (57/57).

2026-06-10 – Make credits screen + dev workflow living-by-default

3a09889 - Twilight

Added the "Keep the Credits Screen Living" and "Default Workflow" sections to CLAUDE.md (auto build+launch, affected-then-full tests before main, debug/profile with logs, green-gated auto commit/push/FF-main) and reconciled the older git-workflow wording.

2026-06-10 – Box-header UX pass

215684b - Twilight

Box-header UX pass – removed the dropdown fill circle (the count conveys fullness), made the current-box marker a leading triangle, and turned the "set current box" control into an Active toggle on both panes (hidden on Party), with the toggle colour-parameterised to read on the accent bar.

2026-06-10 – AI Assistance credits section + ChatGPT status icons

61ae6ea - Twilight

Added a new AI Assistance credits section (Claude, ChatGPT) in display order, and credited ChatGPT under Icons for the in-app status-symbol icons.

2026-06-10 – Notes: storage HP bar + status badges

66e9f72 - Twilight

Documented the storage HP-bar thresholds, the status-badge decode and corner-sharing with the checkbox, and the RGBA asset import workflow.

2026-06-10 – Ignore the assets/icons staging-folder contents

046cdbe - Twilight

Ignored the contents of the assets/icons staging folder (keeping the folder via its .gitignore).

2026-06-10 – Storage-cell HP bar + status badges

3a88495 - Twilight

Each storage mon now shows a narrow colour-coded HP bar (green/amber/red matching GlancePane) between the icon and name, and a status-condition badge in the upper-left that yields the corner to the hover/checked checkbox. Added the model roles and the status icons, decoded from the status byte.

2026-06-09 – Notes: Pokemon storage drag & drop

7d9f22d - Twilight

Documented the storage drag/drop, delete-button, and scoped-checkbox-persistence conventions, plus the icon.width-int gotcha.

2026-06-09 – Drag & drop storage grid (reorder, transfer, delete)

18ee8d3 - Twilight

Made the storage grid cells DropAreas with a manually-driven Drag – dropping reorders within a pane or transfers to the other pane at the drop slot (honouring the checked set as a group, with a dashed insertion caret and a drag threshold so plain clicks still open the editor). Replaced the bulk-action footer with a per-cell delete chip; checkbox selection is scoped to persist only across the editor round-trip.

2026-06-09 – Fix include case for Linux CI

696104d - Twilight

Corrected an include's casing so the case-sensitive Linux CI builds.

2026-06-09 – Stop tracking the root CI helper log/script

b38052b - Twilight

Stopped tracking the root CI helper log/script (_ci.log, _runci.bat) and gitignored the patterns.

2026-06-09 – Begin the Pokemon Selection screen

971caef - Twilight

Began work on the Pokemon Selection screen, with cleanup, fixes, and polish.

2026-06-08 – Capture the comprehensive-testing program (handoff)

b8bacf3 - Twilight

Captured the app-layer testing push and the full comprehensive-testing program as a resumable handoff in the notes.

2026-06-08 – Guard TypesModel's placeholder-row data()

736263b - Twilight

TypesModel's placeholder row 0 fell through to an at(-1) crash for undeclared roles (unreachable from the UI, but a latent crash); it now returns an empty QVariant. The test was extended to drive an undeclared role on every row.

2026-06-08 – Drive PokedexModel's uncovered methods

9e52623 - Twilight

Extended tst_bridge to cover the PokedexModel methods the data() sweep misses – all three sort comparators, the pageClosing reset, the dex lookup hit/miss, and the per-entry change signal – lifting the worst app file off 51%.

2026-06-08 – Exhaustive select-model drive

354c244 - Twilight

A generic driver hits every row x declared role through data() across the select models (types/nature/species/status/starters/move/item/map), plus the index guards, headerData, and each model's value-row helper over edge values. Noted (gated) the placeholder-row undeclared-role crash.

2026-06-08 – db to 90.2%; fix xAlign() guard

07551fb - Twilight

Extended the db getter tests to cover connect-render math, DB base accessors, the qmlProtect cascade, and several entry getters, and fixed MapDBEntryConnect::xAlign()'s guard (it returned 0 for every real map, making its math dead code). All three library layers now >=90%; suite green (56/56).

2026-06-08 – db entry-getter sweep

6693899 - Twilight

Drove every getter over each store with deepLink so resolved-link getters take their non-null path; db overall 75->83%.

2026-06-08 – FontSearch + FontsDB coverage

78d769a - Twilight

Exhaustive sweeps of FontSearch's filters and FontsDB's code conversion/expansion edge cases (driven from each glyph's real name so they stay data-independent), pushing both files into high coverage.

2026-06-08 – common + mapsearch to 100%; fix sprite-set sentinel crash

ac65d4a - Twilight

Covered the Utility/Random QML helpers (common to 100%) and all ~30 MapSearch predicates (mapsearch to 100%), and fixed a sprite-set sentinel bug where the guards treated index 0 as "none" instead of -1, dereferencing a null on maps with no sprite set. db 71.6->75.2%; suite green (53/53).

2026-06-08 – AreaWarps coverage; correct the isType(Cave) note

ef858ac - Twilight

Added AreaWarps setTo/randomize/list coverage and proved that isType(Cave)/isType(Outdoor) match correctly once deepLink resolves the tileset – the long-standing "matches 0 maps" note was a misdiagnosis of the deepLink landmine. Reverted a defensive bound per Twilight (Gen 1 wild tables are fixed at 10). savefile 89.4->90.2%.

2026-06-08 – Fix 3 area bugs + tst_area_logic

5d5b62f - Twilight

Coverage-testing the area family surfaced three bugs (all approved before fixing): an inverted tileset-load ternary that crashed on null and discarded the real tileset otherwise; a Random_Pokedex roll that excluded Bulbasaur (off-by-one on the 0-based dex); and an unbounded setTo array write. Added tst_area_logic regression-guarding all three. Big coverage gains across the area files; suite green (51/51).

2026-06-08 – SpriteData full coverage; crash = deepLink landmine

95307f3 - Twilight

Investigated the documented sprite-link crash first and proved (with deepLink called) that all 918 map sprites resolve cleanly – the crash is purely the tracked deepLink-not-called landmine, not a SpriteData defect. Added a 13-case suite taking spritedata.cpp from 46% to 100%. savefile 82.5->86.5%.

2026-06-08 – Fix isMinEvs() (all-zero, not any-zero)

3cb14a5 - Twilight

isMinEvs() returned true if any single stat-exp was 0; "minimum EVs" means all zero. The real impact: StatsTab's "Reset EVs" was greyed out whenever one stat-exp was 0 even on a heavily-EV'd mon. Fixed and regression-guarded.

2026-06-08 – Fix empty-slot bug in isMaxPP/isHealed

22e1098 - Twilight

The empty-slot bug also lived in isMaxPP()/isMaxPpUps(), which counted an empty move slot as "not maxed" so the heal indicator was wrong for any mon with fewer than four moves; both now skip empty slots. Also tracked the type2 single-write-truth and isMinEvs decisions in next-steps.

2026-06-08 – Fix 3 type/reset bugs in PokemonBox

0dafe96 - Twilight

Fixed three approved type/reset bugs: update(resetType=false) no longer clobbers a dual-type mon's type2 to type1; isCorrected() treats a record as dual-type only when type2 truly differs from type1; and isPokemonReset() judges a reset against the species' real initial moves and PP-Ups. Regression-guarded.

2026-06-08 – PokemonBox/PokemonMove logic tests

586454a - Twilight

New 18-case tst_pokemonbox covering the active PC/party-mon logic the other suites miss – PP-Up clamping, move type/validity, randomize, newPokemon scopes, nature/level clamps, trade-status/OT data, cleanup. savefile 78->82.4%; flagged three latent type/reset quirks (fixed in the following commits).

2026-06-08 – Storage verbs coverage (79->98%)

26af370 - Twilight

Covered Storage's box-space/freeSpace/deposit/randomize verbs, taking storage.cpp from 79% to 98%.

2026-06-08 – Cap recent files at the exact max (off-by-one)

5fb68cc - Twilight

Fixed a MAX+1 off-by-one so the recent-files list caps at exactly the limit; regression-guarded.

2026-06-08 – FileManagement recent-files + load-error coverage

e28796a - Twilight

Covered FileManagement's recent-files handling and load-error reporting (64->77%) and flagged the recent-cap off-by-one fixed alongside.

2026-06-08 – PlayerBasics coverage (67->99%)

c0f09b3 - Twilight

Covered PlayerBasics' OT rewrite, randomizers, and accessors, taking it from 67% to 99%.

2026-06-08 – Item fragment coverage (62->97%)

dfd02c0 - Twilight

Covered the Item fragment's constructors, load, randomize, pricing, and clamping, taking it from 62% to 97%.

2026-06-08 – Record the deepLink landmine + push policy

9023cbc - Twilight

Recorded the latent MapsDB::deepLink landmine and the push-every-commit git policy.

2026-06-08 – SaveFileIterator cursor coverage (57->100%)

24210ca - Twilight

Exhaustively covered the SaveFileIterator cursor, taking it from 57% to 100%.

2026-06-08 – WarpData + MapConnData coverage

881dfa9 - Twilight

Covered the WarpData and MapConnData DB-population and resolve paths (warpdata 54->98%, mapconndata 71->100%).

2026-06-08 – SignData coverage (40->100%)

6eac22b - Twilight

Covered SignData's DB-population and randomize paths, taking signdata.cpp from 40% to 100%.

2026-06-08 – Cross-layer app->savefile->disk e2e

354ebb2 - Twilight

Added tst_app_e2e: edits made through the app layer are saved to a real file, reopened in a fresh manager, and verified – plus a write-and-compare proving the bytes on disk equal the in-memory flatten+recalc buffer exactly. Suite green (41/41).

2026-06-08 – Note engine-providers + QML-behavioural tiers complete

7157b5f - Twilight

Noted the engine-providers and QML-behavioural test tiers as complete.

2026-06-08 – QML behavioural test of the brg.* chain

f6e37cd - Twilight

Added tst_qml_brg, a Qt Quick Test harness that boots a real Bridge and drives the C++-QML property chain from QML (money/coins/playtime read+write, model reachability), guarding the session-13 "undefined chain" regression from QML's side. Suite green (40/40).

2026-06-08 – Cover the graphics engine + image providers

dd36ab9 - Twilight

Added a GUI test compiling the app qrc so the tileset/font PNGs resolve, covering the TilesetEngine builders, TilesetProvider (valid tile + blank fallback), and FontPreviewProvider – closing the last untested app tier. Suite green (39/39).

2026-06-08 – De-flake tst_market_model

60d7c30 - Twilight

The market test segfaulted ~1/3 of runs from creating and destroying a Bridge per test method (the real app never churns Bridges); it now uses one shared Bridge with order-independent assertions. Verified zero crashes in 20 runs.

2026-06-08 – Property-based fuzz of the save round-trip

b16235c - Twilight

Added tst_fuzz – over 150 deterministically-seeded random field combinations asserting every edit persists across a real flatten->recalc->reopen cycle, the checksum stays valid, and flatten is idempotent. Suite green (38/38).

2026-06-08 – Benchmark suite + named regression guards

bff8759 - Twilight

Added tst_bench (benchmarks with hard wall-clock ceilings that fail on a hang) and tst_regression (one named guard per real historical bug). Suite green (37/37).

2026-06-08 – Record app coverage noise; trust the library layers

1cc4acf - Twilight

Recorded that the app coverage percentage is measurement noise, and that the library layers plus functional suites are the trustworthy signal.

2026-06-08 – Cover Game Corner (coins) market accessors

71f801c - Twilight

Added a coins-currency sweep to the market test, covering the Game Corner money/GcPokemon/Message entry subtypes that money-mode never reached. Suite green (35/35).

2026-06-08 – Cover MoveSelectModel list modes

0bea8c6 - Twilight

Covered MoveSelectModel's general all-moves list, the species-specific rebuild path, move-to-row lookup, and the null-mon fallback. Suite green (35/35).

2026-06-08 – PSE_SHARED_APPCORE for clean coverage

7ef91d1 - Twilight

Added an off-by-default PSE_SHARED_APPCORE option so all test exes share one instrumented appcore and llvm-cov merges cleanly – revealing true app coverage of 58.2% line (the earlier 0%/43.6% were static-lib artifacts). The shipped build stays static.

2026-06-08 – Confirm app coverage % is a tooling artifact

8754592 - Twilight

Confirmed the low app coverage figure was a tooling attribution artifact, not a real gap.

2026-06-08 – Correct app coverage to 43.6%

f2c8256 - Twilight

Corrected the app coverage figure to 43.6% using a per-file-max union method.

2026-06-08 – Re-measure coverage + static-link caveat

6eba779 - Twilight

Re-measured coverage (savefile 73, db 62) and noted the app static-link measurement caveat.

2026-06-08 – Round-trip wild-encounter tables and loaded sprites

0aecfe9 - Twilight

Round-tripped the AreaPokemon wild-encounter tables (rates + both 10-slot lists, with grass-swap) and AreaLoadedSprites. Suite green (34/34).

2026-06-08 – Cover ItemStorageModel + checked ops

46a0072 - Twilight

Covered ItemStorageModel's data()/setData() roles, the trailing empty placeholder row, and the checked bulk ops over the BaseSAV bag via a real Bridge. Suite green (33/33).

2026-06-08 – Market buy-checkout + Settings color scheme

8430ad5 - Twilight

Added a buy-mode checkout to the market test (covering the store-item/money subtypes) and a Settings test for colour-scheme derivation and tileset preview-index resolution. Suite green (32/32).

2026-06-08 – Note the case-sensitivity include landmine

c2caa15 - Twilight

Documented the Windows-vs-Linux case-sensitivity include landmine.

2026-06-08 – Fix a case-sensitive include breaking Linux

6ade594 - Twilight

Fixed a wrong-case include (spriteset.h -> spriteSet.h) that Windows accepted but the case-sensitive Linux CI rejected.

2026-06-08 – Re-measure coverage (db 56->63)

aa2bde3 - Twilight

Re-measured coverage after five db suites (db 56->63).

2026-06-08 – AbstractRandomString guard + source coverage

01ec841 - Twilight

Added the canonical negative-index guard to AbstractRandomString::getStoreAt (the same crash as the nine DBs fixed earlier) and covered all five random-string sources, including draw-without-replacement. Suite green (32/32).

2026-06-08 – Sweep map sub-entry getters

18830b1 - Twilight

Swept every map's child sub-entry getters (warps/signs/sprites/wild mons/connections) – the lowest-covered db files – checking getParent() links back. Suite green (31/31).

2026-06-08 – Cover the MapSearch fluent finder

74951ae - Twilight

Covered the MapSearch fluent finder – baseline, disjoint has/no filter behaviour, index-filter edges, accessor agreement, and pickRandom staying within the narrowed set. Suite green (30/30).

2026-06-08 – Cover the GB text codec + FontSearch filters

1197aee - Twilight

Covered the Game Boy text codec round-trip and the FontSearch fluent filters. Suite green (29/29).

2026-06-08 – Exercise ItemDBEntry + MapDBEntry getters

9cddcb5 - Twilight

Drove the getter APIs of the two richest getter-based db entries (ItemDBEntry and MapDBEntry), with size-At consistency checks; noted that price and encounter-rate can be negative sentinels. Suite green (28/28).

2026-06-08 – Re-measure coverage (all layers up)

72182a1 - Twilight

Full 27-suite instrumented re-measure – every layer up (common 79, savefile 72, app 56, db 56); db now the lowest and next focus.

2026-06-08 – Cover the Poke-mart ItemMarketModel

1f3fc4c - Twilight

Covered the Pokemart ItemMarketModel across all four buy/sell x money/coins modes, with cart tracking and a sell checkout that raises the player's money. Suite green (27/27).

2026-06-08 – Cover PokemonStorageModel bulk checked ops

fa260c4 - Twilight

Covered PokemonStorageModel's bulk checked operations (toggle-all, move, delete, transfer) via setData on a real Bridge, with ordering verified by object identity. Suite green (26/26).

2026-06-08 – Cover Random chance/coin helpers + range(float)

0d23337 - Twilight

Covered the Random chance/coin helpers' threshold edges (over 400 iterations) and range(float) bounds including the zero-span case. Suite green (25/25).

2026-06-08 – Correct getStoreAt guards across 9 sub-DBs

8dcac58 - Twilight

CreditsDB::getStoreAt had an inverted guard and eight other DBs missed the negative-index check, so getStoreAt(-1) crashed; all nine now use the canonical (ind<0 || ind>=size) guard. Found by the new store sweep. Suite green (24/24).

2026-06-08 – Cover area child lists

8249e48 - Twilight

Covered the area child lists – warp/sign new/at/swap/remove with byte round-trips, plus sprite list ops and tileset talk-over-tile access. Suite green (23/23).

2026-06-08 – ItemStorageBox + Item behaviour

45a6b84 - Twilight

Covered Item amount-clamp and DB-resolved pricing, and ItemStorageBox add/move/sort/remove/worth/relocate with post-mutation byte round-trips. Suite green (22/22).

2026-06-08 – Cover TilesetEngine wave/blank image math

672e33c - Twilight

Covered the TilesetEngine blank-image and water-wave image math (frame identities, symmetry, rotation wrap) as pure QImage math runnable guiless. Suite green (21/21).

2026-06-08 – Re-measure coverage baseline (app 20->39%)

7cbfac2 - Twilight

Full 20-suite re-measure – app/appcore line coverage nearly doubled on the Bridge suite – recording the per-module table and the exact llvm-cov method.

2026-06-08 – Cover Day Care, Rival, Hall of Fame

176a6dd - Twilight

Covered the Day Care (including the empty-destructor regression path), Rival, and Hall of Fame regions with round-trips. Suite green (20/20).

2026-06-08 – Fix PlayerPokedex::reset() blanking the dex to all-true

b9970f7 - Twilight

reset() passed the dex count as memset's fill value, marking the entire dex seen+owned instead of clearing it (randomize() had masked the bug). The fill value is now 0; found and guarded by the new tst_pokedex. Suite green (19/19).

2026-06-08 – Deep-link sweep + PokemonDBEntry characterization

cf74e18 - Twilight

Per-species verification that every resolved-pointer vector (types, initial moves, TM/HM, learnset, evolutions) lines up with its source and resolves, plus a Bulbasaur characterisation anchor. Confirmed the DB pokedex field is 0-based (the documented dexInd+1 convention). Suite green (18/18).

2026-06-08 – Round-trip the area state tree + PC storage

6cbb1ce - Twilight

Round-tripped the current-area facets (general/audio/player/map/tileset/warp flags) and the Storage container (curBox, boxesFormatted, all 12 boxes). Suite green (17/17).

2026-06-08 – tests_all aggregate so no suite is left unbuilt

111b7e4 - Twilight

ctest had four tests Not Run because CI built a drifting explicit target list; replaced it with a CMake tests_all aggregate depending on every registered test exe, so no suite can be left unbuilt.

2026-06-08 – Record the Bridge suite + two app-layer landmines

7440a38 - Twilight

Recorded the Bridge test suite and two app-layer landmines (the loadScreens static-init requirement and the unchecked getBoxMon/getPartyMon .at() contract).

2026-06-08 – Bridge integration suite for the remaining models

eb832f9 - Twilight

Added a Bridge integration suite that wires every model the way the app does and sweeps each across rows x roles, plus PC storage box ops, the box selector, and Router navigation – covering the previously-untested models. Suite green (16/16).

2026-06-08 – Drop qtdeclarative/qtsvg from the aqt modules

52399a6 - Twilight

Dropped qtdeclarative and qtsvg from the aqt module list (they ship in the Qt 6 base package, not as add-ons), keeping only qtcharts.

2026-06-08 – Update coverage baseline (savefile 67%, app 20%)

5399a58 - Twilight

Updated the coverage baseline (savefile 67%, app 20%).

2026-06-08 – Round-trip remaining world regions

ddbc548 - Twilight

Round-tripped the remaining world regions – hidden items, missables, general flags, and scripts.

2026-06-08 – Round-trip world regions (events/towns/trades/completed)

0142235 - Twilight

Round-tripped the world regions for events, towns, trades, and completion flags.

2026-06-08 – Cover item-select and map-select models

7536595 - Twilight

Covered the item-select and map-select app models.

2026-06-08 – Mark the git remote setup complete

90cee6d - Twilight

Marked the git remote setup complete – default branch main, master removed.

2026-06-07 – Add the git workflow standards

f346525 - Twilight

Added the git workflow standards (main fast-forward-only, frequent dev) and a pointer from the notes.

2026-06-07 – Cover 5 more app-layer models

c7f47bf - Twilight

Covered five more app-layer models – species, move, status, starters, and credits.

2026-06-07 – Test-writing progress

32dc20d - Twilight

Continued progress writing tests.

2026-06-07 – More test-writing progress

fb42d69 - Twilight

Further progress writing tests.

2026-06-07 – More test-writing progress

3a03bfc - Twilight

More progress writing tests.

2026-06-07 – More test-writing progress

db86e38 - Twilight

More progress writing tests.

2026-06-07 – More tests written

4af3e01 - Twilight

More tests written.

2026-06-07 – Further tests written

580bf02 - Twilight

Further tests written.

2026-06-07 – Begin adding testing

eb9686d - Twilight

Began adding the test scaffolding and the first tests.

2026-06-07 – Disable home-screen icons for incomplete features

f01ae86 - Twilight

Disabled the home-screen icons that lead to incomplete features.

2026-06-07 – Fix recent-files bug on moved files + file-open errors

c07d81b - Twilight

Fixed a recent-files bug on moved files and corrected file-open error handling.

2026-06-07 – Slight QML change for comments

852a129 - Twilight

A slight QML change for comments.

2026-06-07 – The documentation commit

31a0341 - Twilight

The big documentation commit – used AI to macro- and micro-analyse the project and produce the initial documentation pass, as part of resurfacing the project before a full manual review. This is the oldest entry in the June 7-14 revival batch the changelog had been missing.

2026-06-06 – Restoration verified; project ~85% resurfaced

480105a - Twilight

Twilight's checkpoint marking the project as fully uncorrupted again after the data-loss scare, and roughly 85% of the way back to where it stood six years earlier. The actual code changes are small cleanups riding along with that milestone: the full-keyboard character picker got tidied up (the search header, criteria, params and the results grid lost some dead weight, with the results view trimmed by a large chunk), a settings tweak in the bridge, a small fix in the main window, and the running notes (status and the fix-patterns reference) were updated to reflect the new state.

2026-06-06 – More restoration progress: builds and opens again

13b6816 - Twilight

A milestone in the recovery: the app compiles and launches once more. This is a small, surgical commit fixing a handful of bugs left over from the earlier data destruction – one-line corrections in the database boot path, the map-select model, and the fonts database – plus notes updates capturing what was wrong and how it was fixed.

2026-06-06 – Manual restoration after corruption and scattered backups

87b9648 - Twilight

A large hand-rebuild pulling the project back together from scattered backups after a corruption event. Touching 78 files across every layer, it restores heavily damaged sources – the Pokemon storage model, the font database and font search, file management, the Hall of Fame and item-storage fragments, area sign/sprite/warp parsing, the rival screen, and the main window among them – and brings the notes system (history, principles, session log, status, fix patterns) back in line. Net it rewrites thousands of lines to undo the damage rather than to add new behavior.

2026-06-05 – AI-assisted revival and modernization begins

c9dc210 - Twilight

The commit that reopens the project after six years and begins modernizing it with AI assistance, with the stated goal of finally finishing the one project Twilight most wanted to complete. It is sweeping – on the order of 400 files – and lays the groundwork for everything that follows: a full CMake build setup across the common/db/savefile/app projects, the entire notes/ knowledge base (architecture, history, principles, decisions, Qt 6 migration patterns, UI patterns, diagnostics, session log), and a broad pass modernizing the C++ and QML to build under Qt 6. Many UI fragments and models are reworked in the process (notably NameDisplay, the Pokemon-details tabs, the Pokemart screen, and the item/move/select models). This is the inflection point between the original 2019-2020 effort and the 2026 revival.