# Shiny Hunter

## [v0.30.0](https://github.com/Nheoz/ShinyHunter/tree/v0.30.0) (2026-08-13)
[Full Changelog](https://github.com/Nheoz/ShinyHunter/compare/v0.25.0...v0.30.0) [Previous Releases](https://github.com/Nheoz/ShinyHunter/releases)

- release: write the release notes for players, not for maintainers  
    The packager builds CurseForge release notes from commit messages unless the  
    metadata points it at a changelog. Commit messages here are written for whoever  
    maintains this next: frame level bands, coordinate frames, retired classifiers.  
    None of that is a reason for a hunter to click update.  
    .pkgmeta now names CHANGELOG.md, and the 0.30.0 entry says what changes for  
    the player: map paws that show what you still need, markers that stay visible,  
    1,004 more places to look, and beasts that no longer send you to empty ground.  
    The project page copy is rewritten the same way and brought up to date -- it  
    still advertised 604 beasts and version 0.21.4.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- release: 0.30.0  
    Play-tested by the user, who reported it working. Their earlier verdict is  
    what unblocked this: the catalogue will always be incomplete, and gets  
    polished by players over time rather than before a release.  
    Covers five versions of unpublished work. CurseForge last received 0.24.3;  
    v0.25.0 was tagged and 0.26 through 0.29.1 never were.  
    Workspace backed up before the bump, per the rule earned on 2026-08-11 when a  
    CurseForge install overwrote the development folder.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- feat: let a player hand their field notes back  
    The catalogue will never be finished, and that is fine: it gets polished by  
    players over time. This is the piece that makes that possible.  
    The addon has been recording the right thing all along. A creature the shipped  
    data does not know is usually one no public source knows either -- a zone  
    released last week has no wiki page and no published coordinates -- so  
    SightingTracker already stores creature id, name, family, classification, the  
    map and the exact spot the player was standing on. ClientFacts already learns  
    display ids the shipped data lacks. None of it could leave the machine.  
    /shiny share builds that into pasteable text and shows it selected. Nothing is  
    sent anywhere: this addon does not contact a website and this does not change  
    that. Where the text goes next is the player's decision, which is also why  
    there is no submit button to mistake for one.  
    The format is what the import pipeline needs, one record per line:  
        # unlisted: npcID|name|family|class|mapID|x|y  
        # displays: npcID|displayID  
    Only creatures the catalogue does not carry are included, so a player who has  
    nothing new to offer is told so rather than handed a wall of text.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- docs: record that the real tameable marker was found  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- tools: retire the invented tameability rule for the real marker  
    Wowhead marks tameable creatures as `Tameable ([url=/pet=<id>/<family>])` on  
    the HTML page. classify\_tameable.py searched for it in the tooltip JSON, where  
    it never appears, got a negative for every creature including The Kurken,  
    concluded the marker was unreliable, and replaced it with a hand-made rule:  
    Beast, names a pet family, classification Normal or Rare.  
    The tool was broken. The data was fine.  
    The player disproved the invented rule three ways: Stumpy and Oro'ohna are  
    Rare Elite Elementals sitting in their stable -- Harandar's fauna reads as  
    Elemental because of the zone and is tamed with an item that grants permission  
    -- and The Golden Serpent is a plain Elite in Kings' Rest.  
    Of the 94 catalogue entries the rule condemned, 90 carry the marker. It would  
    have deleted them. The four that do not include Overfester Hydra, which this  
    player has killed but never tamed: the marker agrees with their own save file  
    without knowing anything about it.  
    check\_tameable\_marker.py replaces it and carries two guards, both earned. A  
    first pass reported zero markers across 94 NPCs -- rapid requests come back  
    HTTP 200 and truncated, and nothing could tell a real negative from a throttled  
    one. So a short page is retried rather than believed, and every run first reads  
    a creature known to carry the marker and aborts if it does not.  
    Still open: the same rule filtered the candidate list when the catalogue was  
    built, so real tameables were dropped before they ever became entries. The  
    Golden Serpent is one. That recovery is not attempted here.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- docs: record that the tameability rule is disproven  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: give 191 entries the trail their source already published  
    An entry added from the player's own sighting was filed with the one  
    coordinate they happened to be standing on, and nothing ever went back for the  
    published set. Looming Mutagenitor shipped one point against seventeen; Gu'chi  
    the Swarmbringer one against sixty-three.  
    The fetcher only ever visited entries with no coordinates at all, so a thin  
    entry looked finished. --thin-below revisits those too and merges: whatever the  
    entry already carries is kept and comes first, because it was either surveyed  
    by a player or already filed against this map, and the published set is an  
    addition rather than a correction.  
    An entry carrying a locationNote is left alone. That note records a decision  
    already taken about its coordinates -- an interior floor dropped, a published  
    point overruled by the player who stood at the spawn -- and refetching would  
    silently undo it. The Kurken keeps its single verified point; Chromehound and  
    Crystalfang keep none.  
    4,444 points to 5,427. 626 of 632 entries now have a trail.  
    Also lands tools/audit\_catalog\_integrity.py, the sweep that found this. Its  
    other finding -- 94 entries that fail the tameability rule -- is deliberately  
    not acted on: the rule is wrong. See the next commit's note.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- docs: record the two-colour paw and the rejected halo  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- feat: draw the map paw in two colours instead of badging it  
    The first attempt put a coloured halo behind the emblem. The player's verdict  
    was that it looked awful, and they were right: a badge stuck behind artwork  
    reads as a sticker, not as design.  
    The paw now exists in two colours and the pin swaps between them. Crimson is a  
    beast still owed; the original turquoise is the reward for having tamed or  
    defeated it. Same silhouette, same alpha, same antialiasing -- the second  
    emblem is derived from the first by tools/make\_paw\_variants.py, so the two can  
    never drift apart in shape or weight.  
    Crimson was chosen by looking at the player's own map rather than by taste:  
    gold collides with the quest exclamation marks, silver with ore nodes, violet  
    with markers other addons already draw. Almost nothing on that map is red.  
    The states differ by hue and never by brightness. The journal already uses  
    desaturation to mean "not obtained", and a faded paw here would give that  
    language a second, contradictory meaning on another surface.  
    An appearance route now answers from the journal rather than showing nothing.  
    A route that names neither a catalogued rare nor an appearance keeps the  
    collected emblem: the addon should not accuse the player of missing something  
    it cannot actually check.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- docs: record the pin frame level fault and the state halo  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- feat: let a map paw say whether the beast is still missing  
    Asked for by the player: reading the map should answer "what do I still need"  
    without hovering every pin.  
    The paw now carries a halo behind it -- crimson while the rare is unclaimed,  
    gold once it has been tamed or defeated, with the emblem itself dimmed slightly  
    so a finished pin recedes. Both colours already existed in the pin's tooltip,  
    so the map introduces no new vocabulary; it just says out loud what the tooltip  
    was only willing to whisper.  
    The halo sits behind the paw rather than tinting it. The journal already uses  
    desaturation to mean "not obtained", and repainting the emblem here would give  
    grey a second, contradictory meaning on a different surface.  
    The four tooltip states and the halo now read one shared table, so they cannot  
    drift apart. An appearance route, which has no captured/defeated record of its  
    own, shows no halo rather than a guess.  
    The provider also listens to RARE\_COLLECTION\_CHANGED now. Rares keep a record  
    separate from appearances, so without it a pin went on claiming the beast was  
    missing until the map was closed and reopened -- exactly when the player has  
    just earned it and is most likely to be looking.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: re-claim the map pin frame level on every acquire  
    The paw was always drawn underneath other addons' pins. It was not the art.  
    Every map addon shares PIN\_FRAME\_LEVEL\_AREA\_POI -- RareScanner, HandyNotes,  
    GatherMate2 and Waypoint UI all request it through HereBeDragons -- and the  
    canvas hands out a higher frame level from that band on each request. The pin  
    on top is whichever one asked most recently.  
    We asked once, in OnLoad, which runs a single time per pin when the pool  
    creates it. Our pins therefore kept their first level for the whole session  
    while every other addon climbed past on each of their own refreshes. Asking  
    again in OnAcquired is what HereBeDragons does; it puts us back in the race  
    instead of permanently at the bottom of it.  
    Ordering between addons is still decided by who refreshes last -- there is no  
    public way to reserve a band above the shared one. This only ensures we are  
    not structurally excluded from the top.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- docs: record the floor-grouping fault and its measured scope  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: drop the two trails measured against an interior floor  
    A full sweep of all 423 entries with published coordinates found exactly two  
    whose points come from a floor other than the zone surface, and in both cases  
    every point does: Chromehound (40) and Crystalfang (5), which live inside  
    Blackrock Mountain. Their coordinates are measured against an interior level's  
    own map, so on the zone map they name open ground.  
    Both keep their zone and lose their trail, with the reason recorded in the  
    entry. The catalogue already knows how to show a beast whose zone is known and  
    whose exact spots are not; it has no way to show that a point is a lie.  
    The sweep is the answer to the question The Kurken raised. Three entries out of  
    423 were affected, and all three are interiors. The other 4,390-odd points were  
    never in doubt: fifteen of them were checked against the player's own recorded  
    sightings and all fifteen landed within 2.5 map points.  
    Report kept in database/floor\_audit.json.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- tools: read spawn points from the surface floor only  
    Wowhead groups spawn coordinates by floor. Key "0" shares its coordinate frame  
    with the zone map every entry is filed against; any other key is an interior  
    level -- a cave, a deck, a dungeon floor -- measured against its own map. All  
    six importers flattened the groups together, so an interior creature's points  
    were plotted on the surface at coordinates that mean nothing there.  
    The Kurken was the entry that exposed it: its cave sits under key "3", which  
    put nine points in the wrong part of Azuremyst Isle until the player stood at  
    the real spawn and read the map.  
    A creature that only has interior points now yields none. No points is a state  
    the catalogue already handles; wrong points send the player to open ground.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: trust the player's own reading over Wowhead for The Kurken  
    The player stood at the spawn and read 45.3 / 19.6 off their map. The nine  
    published points sat at 56-64 / 31-43, a different part of Azuremyst Isle.  
    The published points are not wrong so much as filed under the wrong frame:  
    Wowhead groups spawn coordinates by floor, and The Kurken's are under key "3",  
    the inside of its cave, measured against that level's own map. The import  
    flattened every group into one list and plotted them all on the surface.  
    Its nine points are replaced by the one the player verified, with the reason  
    recorded in the entry so the discrepancy is not silently re-imported later.  
    Fifteen of the player's own recorded sightings were cross-checked against the  
    shipped coordinates first: all fifteen land within 2.5 map points, most within  
    0.5. This is an outlier, not a systemic fault.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- feat: let a dossier name the sub-area, not only the zone  
    Coordinates are filed against the zone map, because that is the map a hunter  
    opens and the one published spawn points are measured against. But "Azuremyst  
    Isle" is a big place, and The Kurken lives in one cave inside it.  
    The player named it: Bastión Semprepino, from standing there. The entry now  
    carries it and the dossier reads "Isla Bruma Azur · Bastión Semprepino".  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: stop settling ambiguous zone names with a coin toss  
    The Kurken was filed by taking the lowest of six map ids that share the name  
    "Azuremyst Isle". It landed on the right one, and the method was still wrong:  
    nothing about a lower id makes it the live zone.  
    Narrowed now by what each step proves -- a zone outranks a dungeon of the same  
    name, because published spawn coordinates are measured against the zone map;  
    then the map this catalogue already files verified rares under. Still tied  
    means unresolved, not guessed.  
    The player asked where the location came from, having tamed the beast  
    somewhere else. Both records are right: they stood on map 99, a sub-area  
    inside Azuremyst Isle, and the shipped coordinates are the zone's. Filing on  
    the zone is the same correction made for the fifteen beasts pinned inside  
    Stonecrag Gorge.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: collect by name and family, not by Blizzard's rare flag  
    The Kurken has a proper name, a skin nothing else wears, and a Normal  
    classification -- so a journal built on the rare flag left it out, along with  
    every beast like it. The flag describes spawn behaviour; a hunter collects a  
    name and a look.  
    632 entries, sixteen of them named tameables the old rule excluded: The  
    Kurken, Gara, Gon, Maximus, Chromehound and others.  
    The tameability test was also wrong. It read the page's "Tameable (Family)"  
    line, which is absent on many pages including The Kurken's -- a beast this  
    player had just tamed, which is what exposed the false negative. The tooltip  
    states it every time: a Beast, a pet family, and a classification. An elite  
    cannot be tamed, and that is the line between Gara and Elegon, The Kurken and  
    Magmadar. Re-running both scans with the corrected rule recovered fifteen  
    entries the first pass had thrown away.  
    Verified: 632 entries, no duplicate ids, 4,444 points inside 0..1 and none on  
    a map other than its own, validator at zero.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: 616 rares, every one with a portrait, and Midnight coverage doubled  
    The 39 entries drawing a paw silhouette now show the beast. The display id is  
    stated on the per-NPC page, for exactly the creatures the client-data export  
    was missing -- so the earlier conclusion that the data did not exist was  
    wrong. It existed; nobody had looked there. 43 filled, none left.  
    Twelve rares added that the catalogue never knew about, including four on The  
    Coiled Isle, a Midnight zone no public catalogue covers. Midnight goes from 12  
    entries to 24.  
    Each cleared four checks read from the source: Beast, Rare, a pet family, and  
    a place. The family is the one that decides -- of 50 rare beasts found, 11  
    have one. The other 39 can be killed but never tamed, and a hunter's journal  
    that does not draw that line is just a list of things to hit.  
    Verified: 616 entries, no duplicate ids, 4,276 points all inside 0..1 and none  
    on a map other than its own, validator at zero.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: add four rares the player met that the catalogue lacked  
    608 entries. Each arrived through the sighting log, which only records a  
    creature whose pet family the client answered -- that answer is what makes a  
    beast tameable, so it is the qualifying evidence, and Destra was tamed  
    outright.  
    Destra is the first entry placed from a player's own field survey: The Coiled  
    Isle shipped with Midnight and no public source carries its creatures, so the  
    map and coordinates come from standing there. Its record says so.  
    Zone names that exist twice were settled first by expansion, then by which map  
    this catalogue already files verified rares under. Neither is a coin toss.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- revert: restore the beacon conditions, and record why they were never the cause  
    The client answered plainly: "beacon: frame=false". C\_Navigation.GetFrame  
    returns nothing for a hunt set from inside a city, so there is no navigation  
    frame to anchor a marker to and no condition here could have revealed one.  
    Both attempts to relax the test are undone. Neither helped, and the second  
    risked bringing back the marker appearing at an arbitrary screen edge, which  
    is the bug the condition exists to prevent.  
    The state diagnostic stays. It is what ended the guessing.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: follow the navigation frame even when the client pins it to the edge  
    When the destination is off screen the client clamps its frame to the nearest  
    edge so an arrow can point past it. That was read as "no valid projection" and  
    everything was hidden, which is why a hunt set inside a city put nothing on  
    screen at all.  
    Clamped is the direction, not a failure. The marker follows the frame wherever  
    the client puts it; only the ground layers -- the beam that claims "the beast  
    is here" -- wait for a projection that is a real place nearby.  
    Also reports the beacon's state when it changes, because "no beacon" has three  
    causes that look identical from the outside: no frame to follow, a frame at  
    the screen edge, or a real one being hidden by our own code.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: show the beacon whenever the client is projecting a position  
    It demanded a distance between 1 and 140 yards. Inside a city the client  
    reports zero, because the destination is not on the current map -- so setting  
    a hunt and looking up showed nothing at all, in exactly the place a beacon is  
    most wanted. That guard was added earlier tonight to stop the beacon appearing  
    at an arbitrary screen position, and it over-corrected from "do not anchor it  
    wrongly" into "never show it".  
    A real projection is the only condition that ever needed to hold. The distance  
    rule existed to stop a decorative ground beam looking like it stood on an  
    intervening cliff at long range, so it now governs the beam alone: the beam  
    waits for the approach, the diamond and the name point the whole way.  
    Found by reading how a working addon decides to draw its own marker: it asks  
    the same client question and does not second-guess the answer.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: import the travel network from Mapzeroth under its MIT licence  
    199 links across 86 maps: portals, ships, zeppelins, trams and flights. The  
    copyright and permission notice are carried in the generated file and the  
    source is named, which is the condition MIT attaches and the use the author  
    licensed it for.  
    The alternative on the table was asking every player to walk through every  
    portal with a slash command. That is not a reasonable thing to ask, and the  
    user was right to refuse it.  
    Faction-restricted links are filtered to the player's own side during the  
    search: standing a Horde hunter in front of an Alliance portal is a worse  
    failure than saying nothing. The importer is kept so the data can be refreshed  
    when Mapzeroth updates -- including when it gains Quel'Thalas, which it does  
    not have yet.  
    TomTom was checked as a source and has no routing data: its only match for  
    "edges" is the pixel size of its arrow.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- feat: carry our own travel network, with no dependency on any other addon  
    The client does not route a waypoint an addon places. Verified at every level  
    of the map hierarchy, from a city map up to the world map: nothing. Other  
    addons solve this by delegating to a travel-graph library the player has to  
    install separately, and the two that exist do not carry Midnight data.  
    So the addon carries its own graph: links between maps, breadth-first for  
    fewest hops, and the first step written into the route card. Fewest hops  
    rather than shortest distance, because every hop is a chance to get lost and  
    distance is not comparable across a portal.  
    The data is gathered by walking it. "/shiny portal" notes where you board,  
    then where you arrive, and writes the link. Both ends are observed on the  
    player's own client, which is the standard the sighting log and the display-id  
    harvest already hold. The shipped table starts empty: pointing a hunter at a  
    portal that is not there is worse than telling them the zone.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: ask for the travel route above the map the player is standing on  
    A journey is not planned on the map of a building. Standing in Silvermoon,  
    GetBestMapForUnit answers with the city's own map, and the client has no travel  
    step for it: the portal that starts the journey belongs to the zone, and the  
    leg after that to the continent. Asking only where the player stands returned  
    nothing for every hunt that needed a portal, which is what the diagnostic  
    showed -- GetNextWaypointForMap(2393) with the player inside Silmermoon.  
    The question now climbs the map hierarchy and stops at the first answer. Four  
    calls at most, once per tick, only while a hunt is running.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- diag: record what the client answers about the next travel leg  
    A screenshot proved the client does route a user waypoint through portals --  
    "Use the Silvermoon portal to Stormwind" is exactly what GetNextWaypointForMap  
    returns as its description. So the capability is there and this addon asks for  
    it, which makes the gap ours.  
    The answer is now logged whenever it changes, so a route that never arrives can  
    be told apart from one that arrives and is dropped. Logged on change rather  
    than every tick because this runs continuously while a hunt is active.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- chore: clear the dead weight before 0.26.0 goes out  
    15 localization strings nothing references, in all six languages. A tool  
    superseded by the one that also disambiguates by expansion. A .gitkeep still  
    shipping in every package for a folder that has had files in it for months.  
    Verified after: 48 Lua files and the XML parse, the manifest matches disk with  
    nothing missing or spare, locale keys are at parity, the data validator is at  
    zero errors, and the catalogue holds 604 entries with no duplicate ids and  
    4,218 points all inside 0..1 on their own maps.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: keep asking the client for the next leg of the journey  
    Blizzard does route a waypoint across the world -- portals, boats -- but not  
    instantly, and the answer changes as the player travels. The route was asked  
    for twice, at the moment of setting the hunt and a quarter of a second later.  
    Both came back empty, the card fell back to "open the map", and nothing asked  
    again: a hunt across continents never showed a step even once the client knew  
    the whole route.  
    Found by checking which APIs a working addon relies on: the same public ones  
    this addon already used, polled rather than asked once. No third-party code or  
    data was copied, and none was needed.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- diag: report the full hunt state, not only its failures  
    "The waypoint does not work" can mean the point was refused, accepted but not  
    tracked, or tracked with the player on another continent where the client has  
    no arrow to draw. Those need different fixes and look identical from outside.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: name the map canvas assertion by reading it, and obey it  
    The diagnostic added earlier pointed at AcquirePin rather than the release  
    call two rounds of guessing had blamed. Blizzard's source says why, in a  
    comment beside the assertion: a pin may not declare OnEnter or OnLeave,  
    because the canvas wires those itself from OnMouseEnter and OnMouseLeave on  
    the pin mixin.  
    So ours did two things at once -- broke the first pin of every template with  
    an assertion, and had their tooltip handlers silently replaced by methods that  
    did not exist. Renaming them fixes the error and makes pin tooltips work for  
    the first time.  
    The XML OnClick goes too: the canvas nils it and dispatches clicks itself  
    through OnPinMouseUp, which calls the mixin method.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: do not abandon the hunt when something steals the tracking arrow  
    Super-tracking has one slot and the client gives it away freely: accepting a  
    quest takes the arrow from the beast the hunter chose. The marker treated that  
    as the hunt being over and hid the route card and beacon together, while the  
    waypoint was still on the map -- which from the outside looks exactly like no  
    waypoint was ever set.  
    Ownership of the waypoint now decides whether the hunt is alive, and the arrow  
    is taken back when it is. Setting a hunt also verifies both halves afterwards  
    and says which one failed, because the client accepts the point silently and  
    then declines to track it.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: settle the zones whose name exists in two expansions  
    35 rares showed as "unknown zone" although their coordinates were published.  
    The name alone could not place them: Shadowmoon Valley is a zone in Outland  
    and a different one in Draenor, and filing one under the other sends the  
    hunter to another continent.  
    The zone endpoint states which expansion it means, and every candidate map  
    sits under a continent whose expansion is not in doubt, so the two facts  
    settle it. Where candidates survived on the same continent they were the same  
    terrain drawn twice -- a zone and its phased variant, identical coastline --  
    and the lower id is taken, which cannot move a point off the map it belongs  
    to. Held to small candidate sets so dungeon floor maps stay unresolved.  
    Coverage: 600 of 604 with trails, 4,218 points. The remaining three are  
    Crystal Fang and the two Karazhan rares, left unfiled rather than guessed.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: audit all 604 rares against the source and fix what it found  
    Full scan, one creature at a time: name, map, coordinates and display id.  
    502 came back clean. The report is kept in database/audit\_report.json.  
    Fixed, each with two independent pieces of evidence agreeing:  
    - 15 beasts filed on a sub-area map rather than the zone their coordinates  
      are measured against. Stonecrag Gorge is an inset inside Nagrand, so 14  
      Draenor rares had every point drawn in the wrong place; same for  
      Skittering Broodmother inside The Maw. Corrected only where the map was a  
      sub-area type AND its parent's name matched the zone the source reports.  
    - 21 entries carrying a wiki page title instead of a creature name.  
    Left alone and reported: 7 map disagreements where our filing is defensible  
    or the parent does not match, and 35 unresolved zones whose names exist in  
    two expansions -- Shadowmoon Valley is both Outland and Draenor, and picking  
    wrong sends the hunter to another continent.  
    Verified after: 604 entries, no duplicate ids, every point inside 0..1, none  
    on a map other than its own record, Skoll's hand-checked points unchanged.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- ui: tell apart the beasts that share a name  
    Madexx is five NPCs in Uldum with five display ids: five skins, five things to  
    collect, one name. The list showed five identical rows, which reads as a bug.  
    Each now says which variant it is.  
    Counted from the entries on screen rather than baked into the data, because  
    the name shown may be one learned from this client.  
    Verified while looking: no npcID appears twice in the 604, and Madexx is the  
    only shared name.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- ui: separate catalogue candidates from the field survey  
    Every uncatalogued creature was filed under "pending research", so a hunter who  
    had walked through Elwynn saw hundreds of boars and wolves listed as chores.  
    The page mixed two unrelated populations and promised work nobody will ever do.  
    A rare the catalogue lacks is a real candidate and is listed with its family,  
    id and where it was met. Ordinary skins are what they always were -- a record  
    of what lives where you walked -- and now say so as a single count.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- feat: record where an uncatalogued beast was met, not just what it was  
    A creature the shipped catalogue does not know is usually one no public source  
    knows either. The Coiled Isle, released with Midnight, has no wiki page and no  
    coordinates published anywhere, so the catalogue holds nothing for it -- and a  
    name without a place can never become a journal entry.  
    For those zones this log is not a convenience, it is the only record that  
    exists. The player standing there is the survey.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: stop refreshing map pins inside Blizzard's own map change  
    Starting a hunt opens the map and changes its zone, and NAVIGATION\_CHANGED  
    arrives inside that call stack. Releasing and acquiring pins while the canvas  
    was still swapping pools is where its assertion came from. The refresh is  
    deferred by a frame, when the canvas has settled.  
    Canvas calls are also reported by name when refused. Blizzard asserts rather  
    than returning an error and its message names only a line number, so two  
    rounds were spent guessing which of our calls it was. It now says which  
    method, which template and which map -- and an unlucky pin no longer aborts  
    the rest of the refresh and leaves the map half drawn.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: keep the world beacon off the screen edge  
    Tracking from another zone put the beacon at an arbitrary screen position.  
    When the destination is not in view the client does not stop positioning its  
    navigation frame: it clamps it to the nearest edge so its own arrow can point  
    off-screen. The beacon anchored to that and claimed a beast was standing  
    there.  
    It now requires a real projection and a non-zero distance, and when it steps  
    back it also forgets the frame it was following, so the next valid tick cannot  
    flash it at the stale edge first. The frame stays shown at zero alpha rather  
    than hidden: it owns the OnUpdate that drives the beacon, and hiding it would  
    freeze the marker for the rest of the hunt.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- data: recover the spawn coordinates the builder was not reading  
    203 of 604 rares had a trail and the rest had a zone at best. A sample of 25  
    missing creatures found coordinates for all 25: the per-NPC source keeps spawn  
    data under map.coords, and the builder looked at the top level, found nothing  
    and reported nothing. Coverage is now 566 of 604, 3,912 points.  
    Coordinates land only on a map already resolved for that creature, or on one  
    derived from entries that know both ids and unanimously agree. Percentages are  
    converted to the 0..1 form used everywhere else, and dense patrol samples are  
    thinned to distinct spots rather than kept whole.  
    Verified: every point inside 0..1, none on a map other than its own record,  
    and Skoll's six hand-checked points unchanged.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- feat: an entry is earned, never asserted  
    Removes the manual capture toggle. Taming and defeating are both watched for,  
    and a button that let the player claim either one made a complete journal  
    prove nothing while devaluing the entries that were actually earned.  
    Recovery does not need the player's word: a stable visit reconciles the whole  
    stable against the catalogue from client data, so a missed capture is still  
    recoverable and still evidence.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
- fix: give the display-id probe a chance to work, and say what happened  
    The probe frame was hidden. A hidden model has nothing to draw, so the client  
    has no reason to stream the creature in, and an unloaded model cannot report  
    its display id. It is now live but parked far off screen at zero alpha.  
    Each outcome is reported once per creature: refused, empty, empty again after  
    a delay, or learned. "Nothing happened" was the one answer that could not be  
    acted on, and it is what we had.  
    Also points the addon list at our own emblem, which shipped unused while a  
    stock bear portrait represented the addon.  
    Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>  
