# Changelog

## [0.21.5] — 2026-08-10

### Changed
- Replaced the minimap and addon metadata icon with a native Hunter pet icon,
  giving Shiny Hunter a clearer beast-companion identity at small sizes.

## [0.21.4] — 2026-08-10

### Fixed
- Field-guide cards are now vertically chained from the lower summary upward,
  rather than positioned with independent fixed offsets. The third step cannot
  overlap the automatic-features panel at any UI scale.

## [0.21.3] — 2026-08-10

### Fixed
- The Field guide's automatic-features panel is now anchored to the journal's
  lower content edge and uses a compact height. It no longer overflows below
  the frame at higher UI scales.

## [0.21.2] — 2026-08-09

### Fixed
- Field-guide cards now use one aligned text column. Removed the duplicate
  floating step numerals that overlapped the first line of each explanation.

## [0.21.1] — 2026-08-09

### Changed
- The in-world hunt marker now uses a warm quest-style beacon with a layered
  glow, a gold search emblem and the selected beast's portrait at its centre.
  The hunter target name sits below the emblem; the native waypoint retains
  distance and route guidance without duplicated text.

## [0.21.0] — 2026-08-09

### Added
- New in-journal **Field guide** tab explains the three-step hunt loop,
  automatic tracking, collection evidence and independent stable snapshot.
- New **Options** tab lets players follow the game-client locale or choose
  English (US/UK), Spanish, German, French, Italian or Brazilian Portuguese
  for Shiny Hunter itself. The journal rebuilds immediately after a change.

### Changed
- Localization is now registered as locale packs and applied from the saved
  setting, instead of being permanently chosen only while the addon loads.

## [0.20.0] — 2026-08-09

### Added
- The main journal, tracking and rare-ledger interface is now localized for
  German (`deDE`), French (`frFR`), Italian (`itIT`) and Brazilian Portuguese
  (`ptBR`) clients. English remains the safe fallback; Spanish continues to
  cover both `esES` and `esMX`.
- Locale packs are layered over the existing English key set, so untranslated
  secondary/debug labels remain readable instead of becoming missing strings.

## [0.19.3] — 2026-08-09

### Fixed
- Nameplate processing now ignores Retail Midnight secret values instead of
  converting protected GUIDs, names or family labels to strings. This prevents
  repeated `NAME_PLATE_UNIT_ADDED` errors while units enter view.

## [0.19.2] — 2026-08-09

### Fixed
- The map provider no longer force-refreshes while Blizzard's world-map canvas
  is still initializing at login. It now lets the normal map lifecycle refresh
  pins, preventing the Retail `Blizzard_MapCanvas.lua:280` assertion.
- Active-pet reconciliation logs a tame only when it newly records the rare,
  so already captured pets no longer flood the chat log after login.

Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
This project uses semantic versioning; while below 1.0, the minor number marks
a roadmap phase.

## [0.19.1] — 2026-08-09

### Fixed
- The native map provider no longer calls Blizzard's pin-pool removal API for
  a Shiny Hunter template before that template has acquired its first pin.
  This prevents the Retail 12.0.7 `Blizzard_MapCanvas.lua:280` assertion at
  login while retaining normal map-pin refreshes afterwards.

## [0.19.0] — 2026-08-09

### Added
- A named rare now completes its journal entry when it is either captured or
  defeated. `PARTY_KILL` records kills directly from the Retail client without
  an external addon dependency.
- Capture and kill evidence are stored independently. Dossiers, sightings and
  map tooltips distinguish `Captured`, `Defeated` and `Captured and defeated`.

### Changed
- Global and territory progress now counts unique recorded rares instead of
  requiring all 604 to remain simultaneously inside the 205-slot stable.
- SavedVariables schema 10 adds the per-character `killedRares` set.

## [0.18.12] — 2026-08-09

### Fixed
- Active-pet reconciliation now falls back to an exact globally unique rare
  name plus matching localized family when Retail replaces the wild NPC id in
  the tamed pet GUID. This recovers Ha'kalawe on `/reload` while rejecting
  shared names and family mismatches.

### Added
- Verified display IDs and family tokens for all five Harandar tameable rares.
  Their list portraits and 3D dossiers now have models, and stable scans can
  identify them by an unambiguous display ID.

## [0.18.11] — 2026-08-09

### Fixed
- Native map-pin XML now binds `OnLoad`, `OnEnter`, `OnLeave` and `OnClick` to
  the pin mixins. Markers are no longer passive images.

### Added
- Hovering a rare skull shows its name, localized family, collection state and
  known search-point count.
- Left-click reveals or hides its coloured search area. Right-click starts or
  stops autonomous tracking from the nearest known point.

## [0.18.10] — 2026-08-09

### Fixed
- Search-area pins now tolerate Blizzard's pool calling `OnReleased` before a
  new pin's first `OnLoad`. The route line is created lazily when acquired and
  released only when it exists.
- This prevents `NAVIGATION_CHANGED` from aborting the map provider before its
  automatic rare skulls are created.

## [0.18.9] — 2026-08-09

### Fixed
- World-map skulls and search areas now use Retail's managed `MapCanvas` data
  provider and pin templates. The previous frames were attached directly to
  `ScrollContainer.Child`; live testing showed that layer behind the visible
  Harandar map, so correct coordinates still produced no visible marker.
- Native pins remain aligned during map zoom and panning. Clicking a skull
  still toggles its coloured search samples and route.
- The `Shiny Hunter` maker's mark is moved from the cartouche's upper seam to
  its measured vertical centre.

### Independence
- The provider uses only Blizzard map mixins and Shiny Hunter's generated
  catalogue. No map library or other addon is loaded or queried.

## [0.18.8] — 2026-08-09

### Changed
- Harandar's five tameable rares now carry their complete currently published
  coordinate samples instead of one representative point: Rhazul 3,
  Ha'kalawe 12, Queen Lashtongue 3, Stumpy 4 and Oro'ohna 4.
- Selecting any of their automatic red skulls can therefore reveal a coloured
  search area or patrol trace, and native tracking receives every known sample.

### Data quality
- The points come from targeted Wowhead NPC metadata and were cross-checked
  against the same five local RareScanner records. The repeated generic point
  `47.2, 50.0` was rejected because it is attached to unrelated Harandar NPCs
  and does not describe any one beast's route.

## [0.18.7] — 2026-08-09

### Fixed
- A successful tame is no longer missed when Retail publishes the replacement
  pet GUID after the first 0.8 seconds. Exact rare ownership is checked over a
  bounded six-second sequence after the relevant pet and cast events.
- Reloading or entering the world now reconciles an independently catalogued
  rare that is already the active pet. This lets a newly tamed Rhazul repair
  its progress immediately after `/reload`, without manual marking.

## [0.18.6] — 2026-08-09

### Fixed
- Harandar now exposes map markers for its five independently catalogued,
  tameable rares: Ha'kalawe, Oro'ohna, Queen Lashtongue, Rhazul and Stumpy.
  Three records were missing coordinates and the other two used older,
  less precise points.
- The generated runtime catalogue remains self-contained; the map overlay does
  not load or query RareScanner.

## [0.18.5] — 2026-08-09

### Fixed
- Dropdowns no longer use the unsupported Unicode `▼` character, which the
  client font rendered as an empty square. They now share a brass-tinted,
  downward-facing `bag-arrow` texture from Retail's native atlas.

## [0.18.4] — 2026-08-09

### Fixed
- The collection summary now names the scope of its capture counter. A regional
  filter reads, for example, `604 total · In Quel'Thalas: 0 / 12 captured`;
  the all-regions view explicitly labels the corresponding figure `Global`.
  This separates filtered results, catalogue size and regional progress.

## [0.18.3] — 2026-08-09

### Added
- The Sightings page now has a persistent field-alert selector: `Ledger only ·
  604` limits cards and sounds to exact NPCs in the independent rare ledger;
  `All rare & exotic` restores alerts for other notable tameable beasts too.
- The preference affects only interruptive alerts. Every valid sighting keeps
  being recorded in the journal regardless of the selected scope.

### Fixed
- The collection search box now preserves `SearchBoxTemplate`'s own text-change
  handler, so its placeholder disappears while typing. Entered text also uses
  the journal's high-contrast ivory instead of the dark inherited font.

### Saved variables
- Schema 9 adds the account-wide `settings.alertScope` preference. Existing
  profiles default to the quieter 604-entry ledger mode.

## [0.18.2] — 2026-08-09

### Fixed
- Named rares are no longer marked captured merely because `Tame Beast`
  reported a successful spell event. The addon now waits for the player's pet
  GUID to confirm that the exact NPC really became the active pet, and clears
  pending captures after interruption, failure or timeout.
- Catalogued rares now trigger their encounter card and nameplate marker even
  when the client has not yet populated `UnitCreatureFamily`; family and model
  information safely fall back to the independent rare ledger.
- `Track beast` now starts the complete automatic patrol at the closest known
  point and keeps its coloured map trail visible. The same control changes to
  `Stop tracking` while that exact NPC is active.
- Regional progress selection now uses an explicit set instead of relying on a
  truthiness expression whose all-regions result was only correct by accident.
- Resetting SavedVariables while the journal is open now refreshes the active
  page as well as its header counter, so stale capture states do not remain on
  screen.

## [0.18.1] — 2026-08-09

### Changed
- `Colección` now contains the complete 604-creature named-rare catalogue and
  a 3D field dossier; the duplicate `Raros` tab has been removed.
- The catalogue filters by continent/region and continues grouping rows by the
  localized zone. The journal counter now measures exact named-rare captures.
- Territory cards are interactive: selecting one opens the collection already
  filtered to that region.
- Sightings now retain catalogued rare encounters per character, show their
  last observed zone and time, and open the corresponding dossier. Unknown
  family members remain in a clearly separated research queue.

### Saved variables
- Schema 8 adds `seenRares[npcID]` with the last observation time, map and
  player coordinates. Migration is additive and preserves all previous data.

## [0.18.0] — 2026-08-09

### Added
- Added an independent runtime ledger of 604 named tameable rares, including
  560 creature models, 548 mapped zones and 212 route-capable records after
  merging the addon's previously verified coordinates.
- Added a `Raros` journal page with instant search, a zone menu, portraits,
  exact NPC ids and direct multi-colour trail selection on Blizzard's map.
- Added exact per-character named-rare capture state. Successful Tame Beast
  casts record the NPC; stable scans safely backfill only unique display ids.

### Changed
- Territory seals now measure the complete named-rare ledger instead of the
  original six rare appearances.
- Catalogued rare NPCs receive encounter alerts and are no longer logged as
  unknown sightings, even when the client classifies their vignette as elite
  or normal rather than `rare`.

### Data provenance
- No RareScanner record, route, coordinate, texture or code is shipped or read
  at runtime. The standalone catalogue is generated from public tameable-family
  pages and factual Blizzard client metadata documented in `docs/data-sources.md`.

## [0.16.0] — 2026-08-09

### Added
- Added `hunter-bestiary-shell.png`, a 1024×640 transparent field-journal
  shell with a reinforced hide spine, bone toggles, restrained brass corners
  and a small turquoise tracking seal.
- Added `hunter-sighting-alert.png`, a distinct 768×256 transparent trophy
  notice with a portrait socket, claw-close seat and integrated action recess.

### Changed
- Replaced the generic `ButtonFrameTemplate` main window with the custom hunter
  journal shell, including its own drag surface, close control, content inset
  and title channel. The window is now 1160×720 and the list narrows to 330 px
  so the decorative spine does not steal space from the creature exhibit.
- Journal tabs now use brass-edged leather plates with a turquoise active rune.
  Inner panels are translucent enough to reveal the authored hide beneath.
- Rebuilt the encounter alert around its own 456×152 trophy plaque. Portrait,
  text, close action and secure target action sit in authored positions; the
  old yellow stripe, generic border, stock close button and red rectangle are
  gone.

## [0.15.12] — 2026-08-09

### Changed
- The turquoise patrol indicator now snaps to the five actual brass route
  details authored into the tracker PNG instead of moving along an approximate
  linear range between them.
- The shared three-slice coordinate calculation is used by both the world route
  instrument and the bestiary tracking plaque, keeping their live indicators
  aligned even though each renders the leather centre at a different width.

## [0.15.11] — 2026-08-09

### Changed
- Migrated the tracker asset from TGA to `hunter-tracker.png` while preserving
  its 1024×256 RGBA pixels and verified alpha channel.
- New project rule: generated interface artwork ships as transparent RGBA PNG,
  with no opaque exterior canvas or black background baked into the asset.

## [0.15.10] — 2026-08-09

### Art
- Replaced the tracker texture's opaque black exterior with genuine alpha
  transparency. The leather writing surface remains opaque; only the canvas
  outside the brass and compass silhouette disappears over the game world.
- The final project asset is an uncompressed 1024×256 RGBA TGA. Its built-in
  background-extraction prompt and conversion provenance are recorded beside
  it in `Assets/UI/README.md`.

### Changed
- Removed the temporary UV margin crop because the transparent asset is now
  fitted directly to its authored silhouette and should use its full bounds.

## [0.15.9] — 2026-08-09

### Changed
- The world route instrument is now 420×104 instead of 540×135, with tighter
  copy, a smaller target title and a progress rail recalibrated to the compact
  silhouette.
- Tracker artwork now crops the narrow opaque safety margin from the shipped
  TGA in UV space. The visible widget ends at its brass frame instead of
  exposing a rectangular black strip around the sides and bottom.

## [0.15.8] — 2026-08-09

### Fixed
- The exact-points button now receives its initial visible label before its
  font region is styled. Retail can return `nil` from `GetFontString()` when a
  bare button still has an empty label; the old unconditional call could stop
  the journal at the same point despite using the correct Font object.
- Multiline Lua failures now repeat their meaningful first line after the stack
  trace, so the concrete error remains visible in short chat windows.

## [0.15.7] — 2026-08-09

### Fixed
- Finished replacing string font names with Retail Font objects. The main
  `Track beast` button was the next construction failure after the exact-points
  control, so the journal could still stop while opening from the minimap.
- Applied the same correction proactively to the sighting alert's combat
  blocker and target button.

## [0.15.6] — 2026-08-09

### Fixed
- Opening the journal from the minimap button no longer aborts immediately
  after constructing its model viewer. The exact-points control now gives
  Retail the actual `GameFontNormalSmall` object instead of its string name.
- Retail's internal `ToDebugString` inspection is no longer reported as a
  missing localization key.
- Lazy window construction now reports a useful stack trace if a later UI
  component fails, rather than silently rebuilding partial viewers on every
  minimap click.

### Changed
- Removed the routine `model viewer created` debug line; successful widget
  construction no longer clutters the diagnostic channel.

## [0.15.5] — 2026-08-09

### Changed
- The route notification is no longer a generic black card. It is now an
  original hunter field instrument built around a teal tracking compass,
  tooled wyvern leather, aged brass and a live route needle. The asset is
  rendered as a three-slice so its authored end pieces never stretch.
- The detail view gains the same visual language in a dedicated field-tracking
  plaque below the model. One prominent `Track beast` action starts or stops
  the full automatic patrol; live progress moves along its brass route rail.
- Exact coordinates are collapsed by default behind `Show exact points`. The
  primary view now shows only hunting ground, recorded-trace count and patrol
  state, keeping raw data available without letting it dominate the exhibit.

### Art
- Added `Assets/UI/hunter-tracker.tga`, an original project texture generated
  for Shiny Hunter and converted to an uncompressed WoW-friendly 1024x256 TGA.
  Its provenance and final prompt are recorded beside the asset.

## [0.15.4] — 2026-08-09

### Added
- Selecting one coordinate now starts an automatic hunt for the appearance,
  rather than tracking an isolated point. Spawn samples are grouped into real
  search zones and ordered by nearest neighbour to reduce backtracking.
- Reaching a search zone starts a three-second observation window. If the
  tracked beast is not detected, the Blizzard waypoint automatically advances
  to the next zone and loops through the patrol. Detecting the target stops the
  route after the encounter alert has been rendered.
- The detail panel distinguishes the active zone from the other locations
  already included in the automatic patrol, and the route card shows progress,
  total zones and live distance.

### Changed
- The projected world beam is now shown only during the final approach. A map
  coordinate has no terrain height, so at long range Blizzard can project its
  X/Y direction onto an intervening cliff. Shiny Hunter now uses the honest
  route card at range instead of making that wall look like the destination.

## [0.15.3] — 2026-08-09

### Fixed
- Search-area points no longer remain invisible when Blizzard's world-map
  addon finishes loading after the map's first `OnShow`. Every refresh now
  explicitly reveals its overlay, including when a coordinate is selected
  while the map is already open.
- Alternative spawn points and the translucent bridges between nearby points
  are larger and more opaque, so a many-coordinate patrol cannot be mistaken
  for the single native Blizzard waypoint.
- Debug output now reports how many search points were drawn and on which
  UiMapID.

## [0.15.2] — 2026-08-09

### Added
- Rare and exotic hunter beasts now raise an original Shiny Hunter encounter
  card when their nameplate enters view or they are targeted. It includes the
  live localized name, family, portrait, sound and secure target action; each
  spawned GUID alerts only once per session.
- The encounter card also works for uncatalogued candidates; verified entries
  such as Aotona and King Krush use their catalogued portrait.
  Sound is now owned by this single alert path, preventing tracked hunts from
  ringing twice.
- The active hunt paints every verified coordinate for that appearance on
  Blizzard's world map. Nearby points merge into a translucent magenta search
  area; the selected point is gold and every spot is click-to-track.
- `tools/audit_hunter_catalog.py` inventories the complete tameable-family
  candidate graph from Warcraft Wiki's CC BY-SA API. It can compare names with
  a local RareScanner installation without importing its protected records.
- Ten verified rare spirit beasts joined the shipped bestiary: Ankha,
  Ban'thalos, Bloodgullet, Bulvinkel, Ghostcrawler, Karoma, Lightning Paw,
  Magria, Myonix and Pashya. Aotona also joins as the first bird-of-prey entry.
  Their patrol samples bring the database to 17 appearances, 17 creatures and
  188 locations.

### Research
- RareScanner declares `All Rights Reserved`. Its pet table describes battle-
  pet drops, not hunter pets, and its rare NPC table does not identify
  tameability. No code, textures, coordinates or database records were copied.
- Warcraft Wiki currently exposes 63 tameable family categories and 5,542
  unique candidate pages. The local rare-name intersection yields 633 review
  candidates; 600 have an NPC ID independently confirmed by the wiki. They
  must be grouped by appearance and verified in batches before shipping.

## [0.15.1] — 2026-08-09

### Fixed
- Tracking a spawn on another continent no longer leaves an invisible active
  state. A compact route card remains on screen until Blizzard can project the
  next waypoint into the world.
- The route card reads `C_SuperTrack.GetNextWaypointForMap` and displays the
  next travel-step description supplied by the client. This lets Blizzard name
  a portal, boat or map transition without maintaining a duplicate route
  network inside Shiny Hunter.
- The world marker is now a single narrow beam, diamond and pet name. Duplicate
  distance and ETA labels were removed because they overlapped Blizzard's own
  waypoint text.

### Added
- When a nameplate or selected target matches the appearance currently being
  tracked, a native WoW warning sound plays once for that spawned creature.
  The alert respects `soundEnabled` and has an eight-second global cooldown.

### Verification
- Static checks pass. Cross-continent travel descriptions, the simplified
  world marker and the tracked-creature sound still require an in-game test.

## [0.15.0] — 2026-08-09

### Added
- Every verified coordinate in `Dónde encontrarla` is now a selectable link.
  Selecting it creates a Blizzard user waypoint and super-tracks that exact
  spawn point; selecting the active coordinate again clears the route.
- `Navigation/NativeWaypoint.lua`: a dependency-free in-world beacon anchored
  to Blizzard's projected navigation frame. It shows the appearance name,
  live distance and an estimated arrival time while the player approaches.
- Hover help and an explicit `[Seguir]` / `[Siguiendo]` state make each spawn
  point independently actionable, including creatures with many coordinates.

### Architecture
- Navigation uses only `C_Map`, `UiMapPoint`, `C_SuperTrack` and
  `C_Navigation`. No external addon is detected, loaded or called.
- The marker's distance sampling is throttled to 0.12 seconds and its
  `OnUpdate` exists only while the marker is visible.
- The obsolete optional dependency declaration and planned external provider
  were removed.

### Verification
- Static Lua parsing, localization coverage and data validation pass. The
  world-space projection, distance, route clearing and cross-zone behaviour
  require confirmation inside World of Warcraft.

## [0.14.3] — 2026-08-09

### Fixed
- Detail text is clipped inside a mouse-wheel scroll region between the model
  and the fixed action buttons. Long coordinate lists can no longer leave the
  panel or draw underneath its controls.
- The favourite marker now uses the client-shipped gold star texture instead
  of a font glyph that rendered as an empty square on the Spanish client.
- Every pet read from the player's stable is shown in full colour and labelled
  as owned. A missing collection record is addon data debt, not an unknown pet.

### Changed
- The visible collection name is now **Hunter's Bestiary** / **Bestiario del
  cazador**. The earlier inspiration name has been removed from source and
  documentation.

## [0.14.2] — 2026-08-09

### Added
- A hunter bestiary presentation for the collection: stable catalogue numbers,
  real creature portraits sourced from each verified display ID, family and
  expansion on every card, and a larger exhibit-style detail view.
- Missing appearances are desaturated in both the list and 3D preview; collected
  appearances regain full colour. The state remains readable through text and
  does not rely on colour alone.
- A compact visual progress bar beside the existing collection counter.

### Changed
- The main window is wider and uses layered ink, leather-brown and gold panels
  instead of a single flat black inset.
- Tabs, filters, action buttons, list headers and selection states now share one
  client-native theme in `UI/Theme.lua`.
- Stable pets use their own display IDs for portraits. Uncatalogued stable pets
  are shown desaturated rather than with a generic family icon only.

### Verification
- Data validation and static Lua parsing pass. Exact layout, portrait masking
  and model desaturation still require confirmation inside World of Warcraft.

## [0.14.1] — 2026-08-09

### Fixed
- Skoll no longer falls back to “exact spawn points not verified”. The six
  precise coordinate pairs published by Wowhead's structured NPC tooltip are
  now stored under The Storm Peaks and generated into `Data/Locations.lua`.
- Source documentation distinguishes Wowhead's zone id from Blizzard's UiMapID;
  only the coordinate pairs cross between those two identifier systems.

## [0.14.0] — 2026-08-09

### Added
- Instant collection search over appearance name, family, expansion, tags,
  creature names, zones and subzones. Search documents are cached when the
  browser layout is built; typing performs no sorting or map API calls.
- Compact filters for collection status (including favourites), family,
  expansion and traits (rare, elite and exotic).
- Filter-aware family headers: empty groups disappear and each counter reflects
  only the matching appearances. A clear empty state replaces a blank list.
- One-button reset for the search and every active filter.

### Performance
- Filtering only rebuilds the data provider. The existing `WowScrollBoxList`
  continues to recycle visible rows rather than creating frames per result.

### Verification
- Static Lua validation and data validation pass. In-game confirmation is still
  required before this phase is considered delivered.

## [0.10.0] — 2026-08-09

**Seen.** The half of a field journal that a plain collection list leaves out.

### Added
- `Collection/SightingTracker.lua`. Target a pet the database knows and it is
  marked **seen** — tamed or not. You can walk past Loque'nahak at level 20,
  fail to tame it, and the journal remembers you found it.
- A new `SEEN` status between missing and collected, shown in the list in blue
  and stated in the detail panel.
- A sighting log: targeting a tameable beast the database does *not* know
  records its creature id, name and family. That is first-party data gathered
  by playing — exactly the candidate list the enumeration phase needs, with no
  external source and no licence attached to it.
- `/shiny sightings` reports the log.

### Changed — SavedVariables (schema 4 → 5)
- `seen` per character, `sightings` account wide. Additive; the migration step
  exists so the version chain does not stall.

### Notes on the implementation
- The creature id comes from splitting the target's GUID and taking the sixth
  field, the way RareScanner does it on this client. Anything whose GUID does
  not start with `Creature` is ignored.
- `UnitCreatureFamily` is **not** observed in use by any addon here, so it is
  capability-checked. It returns the localized family name or nil, which is the
  filter that keeps quest givers and critters out of the log. Without it the
  seen-marking still works and only the log stops.
- `UnitCreatureType` was rejected for that filter: it returns a localized
  string, so comparing it against a literal would break outside English.
- Seen is additive only. Nothing ever un-sees a pet.
- Cost per target change: one GUID split and one hash lookup. No polling.

## [0.9.0] — 2026-08-09

**The addon is now Shiny Hunter.** Renamed while nobody had it installed,
which is the only cheap moment to do it.

### Changed
- Folder, TOC, saved variables, window global and slash commands all renamed.
  `/hc` becomes **`/shiny`**, with `/shinyhunter` as the long form. `/sh` was
  rejected as too likely to collide with another addon.
- `ShinyHunterDB` replaces `HunterCollectionDB`.

### Added
- A `LICENSE`: free to download and use, **all rights reserved**. Redistribution,
  forks and derivative works need written permission. The addon ships as source
  because WoW addons must — the licence is what governs reuse, not secrecy.
- `## X-License` and a real author in the TOC, plus notes written for a public
  listing rather than for a work in progress.

### Consequence
- Saved data does not survive the rename. WoW names the saved-variables file
  after the addon folder, so the old file is orphaned and cannot be read by the
  new one. This affects six pets' worth of marks and nobody but the author, and
  it is precisely why the rename happens now rather than after release.
- **The TrinityCore route is closed.** GPL 2.0 data cannot go into an
  all-rights-reserved addon. The licence question is settled and the data plan
  is now verified batches plus what the addon can learn from play, neither of
  which needs anyone's permission.

## [Unreleased]

### Investigated
- TrinityCore's world database (TDB) as a bulk source for the NPC → display id
  mapping. Report in `docs/data-sources.md`. **No data incorporated.**
- Coverage is far better than assumed: the `master` branch declares support for
  **12.0.7.68974**, the exact build this addon targets, and its latest world
  database (`TDB1200.26021`, February 2026) is three times the size of the
  3.3.5 one. The earlier hypothesis that it would only cover old content was
  wrong.
- Licence is the blocker and remains unresolved. The code is GPL 2.0; the data
  dumps carry **no stated terms at all** in the README, the FAQ or the release
  notes. Two consequences need a human decision: GPL 2.0 is copyleft and would
  apply to the addon, and the EU sui generis database right can attach to bulk
  extraction from a compilation regardless of whether the individual facts are
  copyrightable.

### Noted
- Shiny Hunter declares **no licence at all**. That is a gap worth closing
  whatever is decided about TDB.

## [0.8.0] — 2026-08-09

The data pipeline, brought forward because hand-editing record files stops
scaling at around fifty entries and the collection is meant to reach a few
hundred.

### Added
- `database/hunter_pets.json` — single source of truth. Nests creatures inside
  appearances and locations inside creatures, because that is how a human edits
  it; the generator flattens it into the three flat record files.
- `tools/generate_database.py` — emits `Data/Appearances.lua`,
  `Data/Creatures.lua` and `Data/Locations.lua`. Refuses to write when the data
  does not validate, and is idempotent: a second run changes nothing.
- `tools/validate_data.py` — the cross-record checks of `Data/Validator.lua`,
  run outside the game. A dangling reference or a coordinate written as a
  percentage is now caught when the data is edited rather than after logging in.
- `tools/petdata.py` — shared loader, so the generator and the validator can
  never disagree about what the source file means. It reads the enum and family
  tokens out of `Data/Enums.lua` and `Data/Families.lua` rather than repeating
  them, so the two sides cannot drift apart.
- A `"pending": true` flag for candidates that have not been verified. The
  generator skips them instead of emitting guessed values.

### Changed
- The three record files are now generated and carry a "do not edit by hand"
  header. `Data/Families.lua` is **not** generated: it is complete and comes
  from the client's own `CreatureFamily.db2`.
- `docs/database-schema.md` now states what counts as collectible: notable
  appearances — spirit beasts, named tameable rares, and pets with a special
  obtaining condition. Ordinary family skins are out of scope, and that is a
  data decision rather than a schema one.

### Verified
- The generated files reproduce the six hand-written appearances exactly. The
  only differences are cosmetic: `0.30` renders as `0.3`, and locations are now
  grouped under their creature rather than split between coordinate and
  zone-only sections.
- Editorial notes in the JSON survive into the generated Lua as comments, so
  the "why" a reader needs is not lost to generation.

## [0.7.0] — 2026-08-09

A browser that looks like it belongs in the current game, using the family
icons the database gained in 0.6.1.

### Changed — list
- Rows are 36px and carry the family's own icon, the pet name, and the family
  name as a subtitle underneath it.
- The selected row is a tinted panel rather than a faint wash.
- Family headers carry their icon, their counter, and are **collapsible**.
  A collapsed family is still walked for its totals, so the counter stays
  correct while its rows are simply not emitted.

### Changed — detail panel
- A proper header: the pet's name on the left, the family with its own icon on
  the right, the way the game's own collection panels lay it out.
- The family name is no longer repeated in the line below; that line now
  carries specialization and expansion only.
- The pet's name turns gold when it is a favourite.

### Notes
- `PetList:Create` now takes a callbacks table rather than a single function,
  since the list has two things to report: selection and family collapse.
- Icons use the verified `IconFileID` values from `CreatureFamily.db2`. No
  atlas name has been used that was not observed in use on this client, which
  is why favourites are still shown by tint rather than by a star: an
  unverified texture draws nothing at all rather than failing loudly.

## [0.6.2] — 2026-08-09

### Fixed
- `/shiny validate` with debug enabled printed a dozen alarming-looking rejection
  warnings that came from the self-tests deliberately registering broken
  records. Fixture stores are now created quiet: expected rejections are still
  recorded so the tests can assert on them, they just no longer reach the debug
  channel looking like faults in the shipped data. A diagnostic channel that
  cries wolf is worse than none.

## [0.6.1] — 2026-08-09

Every hunter pet family, from the game's own data.

### Added
- All **61** hunter pet families, with verified `familyID`, icon file id,
  specialization and exotic flag. The list is not a judgement call: it is every
  row of `CreatureFamily.db2` whose `PetTalentType` is not -1, that value
  marking the families that are not hunter pets. The count matches an
  independent list exactly.
- Family names in both locales taken verbatim from the client's own table,
  including its `?locale=esES` export.

### Fixed
- Two hand-written Spanish family names were wrong and are now game data:
  "Bestia de espíritu" → **"Bestia espíritu"**, and "Demonisaurio" →
  **"Demosaurio"**. The second was visible in the stable UI all along.

### Changed
- The validator reports families without appearances as a single summary line
  instead of one warning each. The family table is complete while the
  appearance table deliberately is not, so most families having nothing yet is
  the expected state, and sixty warnings would bury the real findings.
- `Data/Families.lua` is a table plus a registration loop rather than sixty
  repeated literals. Every entry still goes through the same schema validation.

## [0.6.0] — 2026-08-09

The 3D model view. Taken before 0.5 because with six appearances a model can be
verified by looking at it, and a search box cannot.

### Added
- `UI/ModelViewer.lua` on `CreateFrame("PlayerModel")` and `SetDisplayInfo`:
  drag to rotate, mouse wheel to zoom, and a reset button.
- The detail panel shows the model at the top of the pane with the text
  flowing underneath, so a wide creature is not squeezed into a column.
- The main window grew to 620px tall to keep an eight-spawn source list from
  colliding with the buttons.

### Notes on the implementation
- An appearance with no verified display id shows a message, not an empty 3D
  frame. `Model:ClearModel()` is **not** used: it is not in use by any addon on
  this client, so it stays unverified. Hiding the frame achieves the same thing
  with verified behaviour.
- Drag rotation is the one place an `OnUpdate` is unavoidable, since it has to
  sample the cursor between mouse events. The script is installed on mouse down
  and removed on mouse up, and the handler also stops itself if the button is
  no longer held — a mouse-up outside the frame never reaches `OnMouseUp` and
  would otherwise leave it running every frame.
- `SetDisplayID` ignores a repeated id, so refreshing the panel after a
  favourite toggle does not reset a rotation the player just made.

## [0.4.2] — 2026-08-09

The display id gap is closed for the shipped data, and family ids and icons
now come from the game's own tables.

### Added — data
- Every appearance now carries its verified Blizzard display id:
  Loque'nahak 28010, Skoll 29673, Gondria 28871, Arcturis 31094,
  Humar the Pridelord 4424, King Krush 28052.
- Families carry their real `familyID` and `icon` from `CreatureFamily.db2`:
  Spirit Beast 46, Cat 2, Devilsaur 39.
- `tools/fetch_creature_data.py`, a bounded development tool for looking up
  display ids. It takes explicit ids only, refuses more than 25 per run, does
  no crawling, and sleeps between requests. The addon still never touches a
  network.

### Established
- `CreatureFamily.db2` carries `PetTalentType`: 0 Ferocity, 1 Tenacity,
  2 Cunning, and **-1 for families that are not hunter pets** (warlock demons,
  elementals). Confirmed by cross-checking about sixty families against an
  independent specialization list with no disagreement, which makes the full
  hunter family list derivable from game data rather than a judgement call.

### Consequences
- `/shiny validate` should now report 3 warnings instead of 9: the six
  "no display id" warnings are gone.
- The stable scanner has real data to match against. It will still recognise
  none of a typical stable, because the database holds six rares and not the
  spiders and scalehides most hunters actually carry — but the matching is now
  live rather than theoretical.
- The 3D model view is unblocked for phase 0.6.

### Sources tried and rejected, recorded in docs/data-sources.md
- `Creature.db2` looked ideal — it has `DisplayID` and `CreatureFamily`
  columns — but it is a 23,062 row table of pets and summons, not the world NPC
  catalogue. None of the six rares are in it, and it is unsorted, so a
  streaming early exit cannot work either.
- `CreatureCache.wdb` is no longer written by modern retail clients.
- The Wowhead tooltip endpoint has no display id, but does carry 20 spawn
  points for Loque'nahak against the wiki's 8 — a better coordinate source for
  later.

## [0.4.1] — 2026-08-09

The stable snapshot is now remembered, so the addon knows this hunter's pets
away from a stable master.

### Changed — SavedVariables (schema 3 → 4)
- `stableDisplayIDs`, a bare set of ids, became `stablePets`: the client's
  answer stored verbatim, with slot, display id, family name and pet name.
- The 3 → 4 migration converts the old set into snapshot entries carrying the
  display id alone. It cannot invent the fields the old shape never held, and
  the next stable visit fills them in. Nothing is discarded.
- `owned` is now derived from the snapshot rather than stored alongside a
  second copy of the same facts.

### Added
- `/shiny stable` falls back to the saved snapshot when there is no live read, and
  states when it was taken. Previously it reported an empty list, which read as
  "you have no pets" rather than "I cannot see them from here".

### Confirmed in game
- The stable **is** readable with the stable window open: 11 pets returned with
  their display ids. Whether it is readable with the window closed is still
  open; the fallback above makes that difference visible instead of silent.

## [0.4.0] — 2026-08-09

Stable detection, brought forward from phase 0.8: the stable turned out to be a
legitimate first-party source of the display ids the database is missing.

### Added
- `Collection/StableScanner.lua`. Reads the hunter's own stable through
  `C_StableInfo.GetStablePetInfo`, which returns a `displayID` per pet —
  exact and locale independent, unlike family names or the player's own pet
  names.
- Display ids read from the stable are matched against the database and the
  corresponding appearances are marked collected automatically.
- `/shiny stable`: reports whether the client answered, how many pets were read,
  how many were recognised, and lists every display id the database does not
  know. Those ids are verified values from the player's own client.
- `Data/Registry.lua` gained the `appearanceIDByDisplayID` index and
  `API:GetAppearanceIDByDisplayID()` — the bridge from what the client sees to
  what the journal calls it.
- The detail panel states "In your stable" when the last read saw the pet.
- Validator check and three self-tests for the display id index, including the
  clash case: a display id claimed by two appearances would mark the wrong pet.

### Changed — SavedVariables (schema 2 → 3)
- Character records gained `owned`, `stableDisplayIDs` and `stableScannedAt`.
  Purely additive; the migration exists so the version chain does not stall.
- **Ownership is stored separately from `collected`.** Ownership is whatever
  the last read saw; `collected` is the player's journal. Merging them would
  let a stale or partial read overwrite a mark the player made by hand.

### Two rules the scanner follows
- A read that returns nothing leaves everything untouched. Empty means "could
  not read", never "you own nothing".
- The scanner only ever **adds** to `collected`. A pet absent from a read may
  mean the read was partial; concluding the player released it would invent
  information and destroy a mark they cannot recover.

### Known limitations
- The full stable appears to be readable only while the stable window is open —
  see `docs/wow-api.md` for the evidence. Syncing is therefore opportunistic,
  and `/shiny stable` says so plainly instead of showing an empty list.
- The database still holds no display ids, so nothing will be recognised yet.
  Every pet in the stable will be reported as unknown, which is exactly the
  output needed to start filling the gap.

## [0.3.0] — 2026-08-09

The browser. The database is now visible, selectable and markable.

### Added
- `UI/PetList.lua`: virtualized list on Blizzard's `WowScrollBoxList` stack.
  Frames are recycled, so the number of live frames stays proportional to the
  visible area rather than to the size of the database.
- `UI/DetailPanel.lua`: the right hand pane — name, family, specialization,
  expansion, traits, requirements, collection status, and every known spawn
  point with its zone and coordinates.
- `UI/Browser.lua`: turns the database into list elements, grouped by family
  with per-family progress counters, and wires selection through to the detail
  panel.
- Favourite and collected toggles in the detail panel. Beyond the phase's
  stated scope, but `Collection/State.lua` had shipped in 0.1 with no way to
  exercise it: without these the browser's reaction to `COLLECTION_CHANGED`,
  the progress counter and saved-variables persistence could not be tested at
  all.

### Changed
- The main window's placeholder is gone, replaced by the list/detail split.
- Zone names are resolved through `C_Map.GetMapInfo(mapID).name` at display
  time, so they arrive already localized and are not stored in our database.
- Coordinates are converted from the canonical 0..1 to percentages in the
  detail panel only — the single "where a human reads them" boundary.

### Notes on the implementation
- Sorting and state reading are separated: `BuildLayout()` sorts families and
  appearances and runs once, `BuildElements()` walks that cached layout and
  reads only the volatile fields. Toggling a favourite therefore costs one walk
  rather than a re-sort of the database.
- The registry's index arrays are returned by reference, so the browser copies
  them before sorting; sorting in place would reorder the database itself.
- Favourites are shown by tinting the row name rather than with an icon: no
  icon atlas name has been verified, and an unverified texture draws nothing at
  all rather than failing loudly.
- Creature names are still not displayed. `creature.name` is English reference
  data, so a source is identified by where it is found until names can be
  resolved from the client.

## [0.2.0] — 2026-08-09

Data foundation. The model is now real, validated and covered by tests; the
database is deliberately tiny.

### Changed — SavedVariables (schema 1 → 2)
- Character records are now keyed by `UnitGUID("player")` instead of
  `"Name - Realm"`. The old key broke on a character rename and left records
  nothing could identify.
- The character is resolved at `PLAYER_LOGIN` rather than `ADDON_LOADED`: unit
  information is not guaranteed to be populated when saved variables first
  become available, so the old code could have produced a nil key.
- Each character record now stores `name`, `realm`, `class` and `lastLogin` as
  readable metadata alongside the opaque GUID.
- Migration 1 → 2 parks old records in `legacyCharacters` and adopts them onto
  the GUID key as each character logs in. Nothing is deleted.
- `Database:GetAllCharacters()` added, for the account-wide aggregates on the
  roadmap.

### Added — data model
- `Data/Enums.lua`: expansion, specialization, source-type, provenance and
  requirement-kind tokens, each with a localization key. No bare strings
  anywhere else.
- Coordinates are stored in **0..1**, the form every current Blizzard map API
  uses. Sources quoting percentages are converted once, in the data file.
- Extensible requirement system: a `kind` plus a free `params` table, with a
  per-kind parameter contract. Ten kinds defined; adding one is a single entry.
- Schema field constraints are declarative (`required`, `enum`, `min`, `max`,
  `element`), so type, range and enum checks share one code path.
- Facts are no longer duplicated across records: a creature has no family or
  locations of its own, and an appearance has no creature list. Those are
  reached through derived lookups and indexes.

### Added — registry and queries
- `ns.Data.API`: the single query surface, every call a hash lookup.
- Indexes built at registration for family, expansion, appearance, map,
  creature and location lookups. `creatureIDsByMap` is deduplicated.
- `Registry:NewStore()` / `RegisterInto()`, so tests exercise the real
  index-building code rather than a copy of it.
- `API:GetEffectiveRequirements()` merges family, appearance and creature level
  requirements without repeats.

### Added — validation
- `Data/Validator.lua` and `/shiny validate`: dangling references, orphans,
  invalid map ids, out-of-range or half-missing coordinates, contradictory
  level ranges, unknown expansion tokens, reference cycles and provenance.
  Errors and warnings are reported separately — a thin database is not a broken
  one.
- `Tests/DataValidation.lua`: 26 self-tests over throwaway stores and the
  shipped data, including the one-appearance-many-creatures relationship and
  map deduplication.

### Added — data (all `DATA_REAL_VERIFIED`)
- 3 families: Spirit Beast, Cat, Devilsaur.
- 6 appearances and 6 creatures: Loque'nahak, Skoll, Gondria, Arcturis,
  Humar the Pridelord, King Krush.
- 13 location records across 5 zones.
- 1 requirement: Beast Mastery, referenced by the two exotic families.
- Sources and licences recorded in `docs/data-sources.md`.

### Fixed
- The main window's progress counter was anchored underneath the template's
  close button and was invisible. It now sits above the content inset.
- Slash input with more than three words no longer falls through to opening the
  window.

### Known gaps
- **No Blizzard display id could be verified**, so `appearance.displayIDs` is
  empty everywhere and the future model panel has nothing to show. Reported as
  a warning per appearance.
- Blizzard numeric `familyID` values and family icons are likewise unverified
  and therefore absent.
- No shipped appearance has more than one creature. The relationship is
  supported, indexed and tested against a fixture; asserting it with real data
  needs display ids we do not have.

## [0.1.0] — 2026-08-09

First skeleton. Architecture only: no pet data ships in this version.

### Added
- Addon loads on Retail 12.0.7 (TOC interface `120007`).
- Private namespace and a small module registry with `OnInitialize` /
  `OnEnable` lifecycle, driven in explicit TOC order (`Core/Bootstrap.lua`,
  `Core/Init.lua`).
- `ShinyHunterDB` saved variables with defaults, `schemaVersion`, forward
  migrations, and read-only protection against data written by a newer build
  (`Core/Database.lua`).
- Settings access layer (`Core/Config.lua`).
- Shared event dispatcher and internal message bus over a single frame, with no
  `OnUpdate` anywhere (`Core/Events.lua`).
- Debug channel, off by default, with a ring buffer that captures start-up so
  `/shiny debug dump` can report it after the fact (`Core/Debug.lua`).
- Slash commands `/shiny` and `/shinyhunter`: open, `help`, `version`,
  `debug`, `debug dump`, `reset` with mandatory confirmation
  (`Core/Commands.lua`).
- Record schema and validator for families, appearances, creatures, locations
  and requirements (`Data/Schema.lua`).
- In-memory data registry with the indexes the browser will need, plus
  cross-reference checks at start-up (`Data/Registry.lua`).
- Collection state layer, fully separate from the static data: collected,
  pending, favourite, ignored, and progress aggregation
  (`Collection/State.lua`).
- Main window on `ButtonFrameTemplate`: movable, position persisted, closes
  with ESC, built lazily on first open (`UI/MainWindow.lua`).
- English and Spanish locales, with English as the fallback for any missing key
  (`Localization/`).
- Documentation: architecture, database schema, and a WoW API table recording
  how each call was verified and what remains unproven.

### Notes
- Zero pet records are registered in this version, by design.
- `Navigation/` and `Tests/` exist but are empty; they are reserved for phases
  0.7 and 0.12.
