promotional bannermobile promotional banner

Outfitter Reborn (Midnight)

Clothing and weapon management and automated equipment changes
Back to Files

1.0.0-release

File nameOutfitter-1.0.0-release.zip
Uploaded
Sep 16, 2026
Downloads
7
Size
908.1 KB
Flavors
Retail
File ID
8894908
Type
R
Release
Supported game versions
  • 12.1.0

What's new

commit 0e693d71625e3773fd58387008b00bf15f823366
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 17:24:34 2026 +0530

    Dummy commit for 1.0.0 release

    Carries no changes. It exists only as something to hang the 1.0.0 tag on,
    so the CurseForge packager builds from a commit that means nothing else.

    This supersedes f88302d, which was created for the same purpose and then
    buried under four commits -- the manual move, the CurseForge project ID,
    the author line and the release notes all landed after it. Tagging that
    one now would ship a 1.0.0 without any of them, and without the project
    ID the packager would not know where to upload.

    The tree is identical to b721f7e.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit b721f7e9bcc59fc87e384b14c059b9249f0538ca
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 17:17:08 2026 +0530

    Credit mundocani in the TOC, and shorten the release notes

    The TOC author line uses the CurseForge handle rather than the full name,
    matching how the addon is credited on the project page. The About panel
    and the README credits keep "John Stephen" -- prose and a metadata field
    want different registers, and both point at the same person.

    The 1.0.0 release notes were unreadable: bullets up to 270 characters, so
    the cell wrapped into paragraphs and the bullets stopped helping. Longest
    is now 133. The change is mostly dropping the explanation and keeping the
    outcome -- "Fixed the per-slot checkboxes on the character sheet, which
    were invisible behind any addon drawing over the character panel" is now
    "Character sheet slot checkboxes are visible again". Someone reading a
    changelog wants to know what is different; the why is in the commits.

    The battleground entry is split in two. It carried both the fix and the
    list of newly supported maps, which is what ran it to four lines.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit a78fe7c4404be54cf374aeabbba9c83e2c69f028
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 17:13:36 2026 +0530

    Add the CurseForge project ID to the TOC

    X-Curse-Project-ID: 1698220, using the field name and placement the
    sibling addons use rather than inventing one.

    Pinned by a test. A missing ID fails the upload loudly; a mistyped one
    uploads successfully to somebody else's project, which is the failure
    worth catching.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit 331152eaecfd8c5ad732625f507cf503196216b1
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 17:12:56 2026 +0530

    Move the manual to the root, drop the rest of Documentation/

    UsersManual.md now sits at the repo root. Documentation/ is gone, taking
    RevisionHistory.txt, which stopped at version 5.20.3, and the six JPEGs
    with it.

    Deleting those JPEGs would have left the manual with five dead image
    links, so its screenshots are rewired to the five new PNGs under
    Media/Screenshots. Each one was opened and matched to a section rather
    than guessed from the filename:

      01  the outfit list        (was OutfitterUI.jpg)
      03  the New Outfit dialog  (was NewOutfit.jpg)
      02  an outfit's menu       new, in Automatic switching
      05  the outfit bar         new
      04  the icon picker        new

    Three sections lose their screenshot with nothing to replace it: the
    character sheet's robe button, the minimap menu and QuickSlots. Those
    image lines are removed rather than left broken.

    The new references are absolute raw.githubusercontent.com URLs, and that
    is forced rather than stylistic: the manual ships to players now that it
    is at the root, and Media/ deliberately does not, so a relative link would
    render on GitHub and be a broken image in every player's copy. The test
    that catches exactly that mistake is updated for the new location.

    Also includes your README change. The slash command table is gone from the
    README, which now points at `/outfitter help` and the manual instead. That
    retires the README as a command surface, so the tests that read its table
    are rewritten against the manual: dispatch, in-game help and the manual
    are the three surfaces checked against each other now. A new case fails if
    a command table ever reappears in the README, since that would be a fourth
    surface nothing watches.

    One typo fixed in the line you added: "avaulable" to "available".

    Package is 79 files, 3.35 MB, down from 86 and 3.70 MB.

    Suite 143 passed / 0 failed; luacheck 0/0 over 43 files.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit f88302de3f696cd6e1b78728d9d98985d76d70b0
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 16:57:17 2026 +0530

    Dummy commit to push to Curseforge

    Carries no changes. It exists only as something to hang a release tag on,
    so the CurseForge packager has a commit to build 1.0.0 from without that
    tag landing on a commit that meant something else.

    The tree is identical to 696e7a7. Everything 1.0.0 ships is already in the
    history above this.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit 696e7a77a4d734dcc66a3709fa662d16c433cb61
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 16:48:06 2026 +0530

    Add project screenshots, kept out of the addon zip

    Five PNGs under Media/Screenshots for the project listing and the
    GitHub-rendered docs.

    No .pkgmeta change was needed to exclude them: Media/ has been on the
    ignore list since the logo went in, so anything added under it is already
    out of the download. The comment there was stale about what Media/ holds
    and how big it is, and now says so, along with the constraint below.

    That constraint is the trap worth guarding. Documentation/ ships and
    Media/ does not, so a relative image link from the user manual into
    Media/ renders perfectly on GitHub and is a broken image for every player
    who opens the shipped copy -- invisible to whoever writes it. A new test
    walks the manual's relative links and fails if any resolves into a path
    .pkgmeta excludes. Absolute URLs are deliberately not checked; those
    resolve from the web wherever the manual is read.

    Package is 86 files, 3.7 MB shipped against 9.9 MB kept back.

    Suite 143 passed / 0 failed; luacheck 0/0 over 43 files.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit ba68232c93ca22d13ce9f779147886b470300c5a
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 16:47:55 2026 +0530

    Drop the version from the About heading

    The yellow heading read "About Outfitter Reborn 1.0.0" directly under a
    title bar already reading "Outfitter Reborn 1.0.0". It now reads "About
    Outfitter Reborn"; the title bar keeps the version.

    Two edits rather than one, because the version came from a format
    specifier and not from the string: cAboutTitle loses its %s, and
    OutfitterAbout.lua stops calling :format on it. Leaving the :format would
    have worked -- Lua ignores a surplus argument when there is no specifier
    -- but it would read as though a version were still being inserted.

    Only English ever had that %s. All six locale files already defined
    cAboutTitle without one, so the version was showing in the About heading
    for English players and nobody else; this makes English match the rest
    rather than making it the exception.

    Also includes your README tidy: the "fuller guide" line is redundant now
    that the Usage section links the manual, and the retired-features intro is
    shorter.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit b2a8d4989064ee5ef07bfa1ba3de93a709681eec
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 13:57:09 2026 +0530

    Fit the tab, line up the headers, and point the README at the manual

    The outfit tab is back to "Outfitter". "Outfitter Reborn" overflows it, so
    the tab is the one surface that keeps the short name -- reverted in the
    five locales that override it as well, with a comment saying why so it is
    not "fixed" back later.

    The window's two headers never lined up with each other, and each was
    right by its own rule. The title bar was anchored at x = -10, nudged left
    to look centred in the space beside the close button; the yellow panel
    heading below it centres on the frame. Ten pixels apart reads as sloppy
    without being visibly wrong. Both centre on the frame now, and the reason
    for the old offset is recorded in the XML rather than lost.

    The white title bar text was left in place rather than removed. It is
    window chrome shown on all three tabs and the only place the version
    appears outside the About panel, so deleting it would leave Options and
    About with no title at all. The duplication is specific to the Outfitter
    tab, where the panel heading repeats the window title; that heading is the
    removable one if it still reads as redundant in game.

    README: Installing is replaced by Usage, a short paragraph on the actual
    flow that hands off to the user manual on GitHub. Nothing is lost -- the
    restart-fully warning, which is this addon's most common support issue,
    has a fuller home in Documentation/UsersManual.md.

    Version history highlights are now one bullet per line. Markdown will not
    render a list inside a table cell, so the literal "- " before each <br>
    item is the fix rather than a workaround; without it an eight-item release
    row renders as a single justified paragraph.

    Suite 142 passed / 0 failed; luacheck 0/0 over 43 files.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit d61412968a6dff753c9a1ab9af85536a34416838
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 13:09:09 2026 +0530

    Outfitter Reborn 1.0.0, for Midnight 12.1

    Renames the addon in the UI, retargets it at 12.1, and replaces the user
    manual, which described an addon that has not existed for years.

    The rename is display only. cTitle is now "Outfitter Reborn" and every
    window follows it, including all six locale files -- each of them overrode
    the name, so without that non-English players would still see the old one.
    Russian keeps its own word for the tab, which is a translation of the
    concept rather than the product name.

    cTitle was doing two jobs: the visible label AND the LibDataBroker object
    key. Broker displays store their per-object settings against that key, so
    renaming it would silently reset everyone's broker configuration. The
    identity is now cBrokerName, which stays "Outfitter" permanently, and
    three tests pin the split.

    Nothing else about the addon's identity moves: the folder, Outfitter.toc,
    gOutfitter_Settings and gOutfitter_GlobalSettings are all untouched, and a
    test asserts the saved-variable names specifically -- renaming either one
    throws away every existing user's outfits.

    ## Title does change, because it is the only source for the addon shelf
    and the in-game AddOns list.

    Version is 1.0.0 and Interface is 120100. Both are deliberate and both
    have a consequence worth recording: 1.0.0 is LOWER than the 12.1.0.3 it
    replaces, so updaters may not offer it to anyone already on that build,
    and dropping 120007 means 12.0.7 clients will flag it out of date.

    The About panel now credits both authors, and the TOC author line lists
    them. The README gains a version history table in the format the sibling
    addons use.

    Documentation/UsersManual.html is replaced by UsersManual.md, rewritten
    rather than converted. The old one named categories that no longer exist
    (Complete Wardrobes, Mix-n-match, Special Occasions, against today's
    Complete outfits and Accessories), used NO_ event prefixes where the addon
    uses NOT_, and documented warrior stances, hunter aspects, priest
    Shadowform and druid Aquatic Form, none of which the game still has. It
    now covers the slot checkboxes, which it never mentioned at all, the
    battleground and arena detection, the full command list and a current
    scripting reference. The five existing screenshots are reused with a note
    that they predate the rename.

    Two more tests keep it honest: its command table must match the README's,
    and every screenshot it references must exist.

    Suite 142 passed / 0 failed; luacheck 0/0 over 43 files.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit 1539cc11aaacfc8d1a9acb438e30594adde5950d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 12:47:46 2026 +0530

    Rewrite the README in plainer prose

    Two edits in one: the "Working on it" section is gone, and the rest reads
    less like it was generated.

    The section described the test harness, which is maintainer detail in a
    file aimed at players. It was also the only player-facing statement that
    tests/ and Media/ do not ship; that fact now lives in CLAUDE.md and is
    enforced by the packaging tests rather than asserted in prose.

    The prose changes are mechanical tells, mostly mine. Thirteen em dashes
    down to zero, every one of them doing a comma's or a colon's job. The
    eight feature bullets were all the same `**Bold** - restatement` shape,
    which is scaffolding rather than emphasis once it repeats that many times;
    they are four paragraphs now, ending on a short sentence where the
    interesting part runs out. The install warning was reordered so the
    reassurance lands after the symptoms instead of before them, and the
    credits have subjects again rather than "kept alive since by the
    community".

    No first person was added. This file speaks for the project, and inventing
    a voice for it would be its own kind of wrong.

    Command table untouched: tests/test_commands.lua reads it as a third
    surface, and the suite stays at 133 passed / 0 failed.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit 300288adcab01108fc34d6876805a486ee253bed
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 12:22:40 2026 +0530

    Close out the review: remaining findings, and regression tests

    The last four findings, plus tests for every bug the earlier commit fixed.
    A fix without a test is a patch, and this review's lesson was precisely
    that a green suite can be worth less than it looks.

    F-015: the Deprecated.lua header claimed nothing in the file touches the
    live Outfitter tables. That is false and deliberately so -- preserved
    bodies open `local self = Outfitter` and call live methods, because a body
    with its calls rewritten is no longer the thing that was retired and could
    not be revived by pasting it back. The header now says what is actually
    true: nothing live calls IN, and the only names added to the live table are
    Deprecated and DeprecatedFeature. Two case names that claimed more than
    they checked were renamed to match.

    F-021: the README documented 17 commands; the in-game help documents 21.
    The four missing ones are added, the combined disable/enable row is split,
    and test_commands.lua now treats the README as a third surface -- it
    already checked dispatch against help in both directions, but nothing read
    the README, which is how it drifted.

    F-022: run-all.sh wrote the BOM-stripped copy to a fixed /tmp path that two
    concurrent runs would collide on, now mktemp with a trap. run.lua listed
    files with `find`, which swept untracked scratch .lua files into the
    discipline checks and broke on a repo path containing a quote; now
    `git ls-files`.

    F-023: one DeprecatedFeature label was a feature description and another a
    method name, formatted into the same sentence.

    One more bug, found by the new tests rather than by the review: PlayerIsFull
    had a THIRD fallback branch going the wrong way. An unreadable power type
    defaulted to -1, took the `~= 0` path and reported the player full -- for
    exactly the reason it could not tell. Same direction as the other two now.

    New regression cases, each verified to fail against the original bug:
    - the removal walk-back, driven through the real outfit stack because
      RemoveOutfit returns early otherwise
    - all five securable APIs, asserting none of them ever reports "full"
    - PreviousManaLevel surviving a secret window
    - the equipment update count: balanced pairs, an unmatched End clamping at
      zero, a stranded count clearing, and the reset staying quiet when clean

    Suite 133 passed / 0 failed across 23 suites; luacheck 0/0 over 43 files.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit 430a582a9d48eae457fda8ce0b5a276c5278eba0
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 12:19:04 2026 +0530

    Fix the review's correctness findings, and make three tests falsifiable

    Addon bugs (F-004, F-010, F-011, F-012, F-019, and one found while fixing
    them):

    - RemoveOutfit's fallback walk-back used `#t` as a truth test in two
      places, which is always true in Lua. The break fired after one iteration,
      so the walk back through the recent-complete history has never run:
      removing a Complete outfit whose predecessor was renamed or deleted left
      the player wearing nothing. Now `> 0` and `== 0`.
    - The same mistake at :3205 counted a BoEs header row that was not there,
      overshooting the item list scroll by one. The correct spelling was eight
      lines above it.
    - PlayerIsFull returned true when power was unreadable, reporting the
      player full and taking the dining outfit off mid-meal -- the opposite of
      what its own comment says it does.
    - A secret power reading wiped PreviousManaLevel, so the next real sample
      read as a mana drop and could cancel the Spirit outfit with no drop.
    - CheckDatabase asserted two contradictory invariants about Settings.Outfits
      twelve lines apart. Outfits is now created in InitializeSettings and the
      guards are gone; the two unguarded vOutfit.Items loops are guarded to
      match the third, which is what a pre-6.2 saved-variable file needs to
      avoid raising inside Initialize.
    - An item link read at :4055 went straight into a truthiness test without
      the OutfitterAPI seam -- exactly the inspection Compat.lua warns about.
      Found by the rewritten discipline check below.

    UpdateZone (F-003) gated on GetZoneText(), the localized name the map-ID
    rebuild disowned, while everything below it is map-ID driven. Ashran and
    Battle for Wintergrasp each name both an outdoor zone and a battleground
    instance, and for those the refresh was skipped entirely. It now compares
    instance type and map ID.

    EquipmentUpdateCount (F-009) is bracketed manually at seventeen sites and
    an error between Begin and End stopped equipment updates for the session,
    recoverable only by /reload with nothing saying why. End now refuses to go
    negative and reports an unmatched call, PlayerEnteringWorld clears a
    stranded count, and /outfitter zone reports one. Deliberately NOT pcall
    around the regions: that trades a visible stuck state for a swallowed error.

    Three tests that could not fail (F-001, F-002, F-008):

    - The preset-event whitelist carried an `^[A-Z_]+$` escape hatch that
      swallowed every realistically-named event. It now checks against
      tests/client_events.lua -- 1523 event names extracted from Blizzard's
      published UI source rather than typed -- plus BuiltinEvents and the
      addon's own outfit events. Verified by re-running the reviewer's
      mutation: BOGUS_EVENT_XYZ on a live preset now fails the suite.
    - run.lua recorded Ctx.initOK and no suite read it. Asserting it
      immediately exposed that Initialize() had been raising the whole time on
      a missing debugstack global -- so initialization was never actually
      exercised. Fixed in the mock; two cases now pin both that it completes
      and that it produced the state the addon assumes.
    - The secret-discipline check looked for a call next to a comparison, which
      is not how this codebase reads a value. It now checks the binding, with
      a short lookahead for the bind-then-unsecret idiom, and carries a case
      that exercises the matcher itself.

    Mock fidelity (F-005, F-006, F-007, F-013): the SECRET sentinel now raises
    on arithmetic, comparison, concatenation, tostring, indexing and calls
    rather than only answering issecretvalue; RegisterEvent rejects events the
    client does not have; item links, aura data and UnitStat can be made
    secret; bit.band/bor/bxor actually mask instead of returning their first
    argument. One gap is documented rather than papered over: Lua 5.1 has no
    metamethod for a truthiness test, so Compat.lua's warning that even `if v`
    is an inspection cannot be enforced outside a client.

    F-016's locale check was filtered by a name-suffix allow-list and an escape
    that passed anything already on the Outfitter table. Both are gone; the
    data tables that share the `c` prefix are named explicitly.

    Dead code (F-017, F-018, F-020): the orphaned VOID_DEPOSIT_MAX and a
    duplicated repair block removed, InBattlegroundZone's eight-local
    destructure cut to the one it reads, and two unreferenced textures dropped
    from the zip via .pkgmeta. InZoneType is kept rather than retired: it has
    no caller here but it is a method on the global table that a user script
    can call, and retiring working API is not the same as removing dead code.

    Suite 120 passed / 0 failed; luacheck 0/0 over 43 files.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit ac072fe3fc1c21fb7edfe21e867e5dea7bd909ee
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 12:06:34 2026 +0530

    Record the 2026-09-16 review, and keep it out of the zip

    The frozen bundle from wow-addon:review: findings, proposed changes, smoke
    tests, execution plan and summary. Nothing in it is applied -- it is
    evidence of what was believed on the day, and the proposals are the
    reviewer's, not decisions.

    Verdict was minor issues, 0 critical. The four High findings are worth
    naming here because three of them are about this repo's own test harness
    rather than the addon:

    - The preset-event whitelist in tests/test_scripts.lua cannot fail; its
      ^[A-Z_]+$ escape hatch swallows every realistically-named event. Proven
      by mutation, not by reading.
    - tests/run.lua computes Ctx.initOK and Ctx.initError and no suite reads
      them, so a raising Initialize() still passes.
    - Outfitter:UpdateZone still gates on GetZoneText(), the localized name
      the map-ID rebuild disowned. The zone tests cover GetCurrentZoneIDs and
      never the function the client calls.
    - Three bare `#t` truth tests in Outfitter.lua, which are always true in
      Lua. The one at :3468 breaks RemoveOutfit's walk-back after a single
      iteration, so it has never run. Verified independently before recording:
      the correct `#vWarboundItems > 0` sits eight lines above the broken
      `#vBoEItems` at :3205.

    .pkgmeta now excludes docs/, so review, audit and test bundles stay out of
    the player download. Documentation/ is NOT excluded -- that is the user
    manual and it ships; the two directory names are one letter apart, which
    is why the packaging test now names both.

    That test also gained the half it was missing. It asserted only that three
    entries ARE ignored and never the converse, so an ignore entry that should
    not be there was invisible to it. It now checks both directions.

    Suite at 117 passed, 0 failed; luacheck 0/0.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit 8ff8a26493d290b2ef76040e6383bb40d36faea9
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 11:32:01 2026 +0530

    Add a TGA logo and keep the artwork out of the addon zip

    outfitter.logo.tga is converted from the PNG at its native 1264x1264,
    32-bit uncompressed (TGA image type 2) with an opaque alpha channel added,
    since the source is RGB.

    None of the three logo files is referenced by any shipped file -- they are
    project artwork rather than in-game textures -- so .pkgmeta now keeps the
    whole Media/ directory out of the package, along with tests/, .luacheckrc
    and CLAUDE.md. That is 8.6 MB of the repository that no longer lands in a
    player's AddOns folder; the zip goes from 12.3 MB to 3.7 MB, most of the
    saving being the TGA.

    Four tests cover the manifest: that Media, tests and .luacheckrc are
    ignored, that package-as names the addon, that the TOC never loads a file
    .pkgmeta excludes (which would ship a half-loading addon), and that no
    shipped file references Media/ -- if one ever does, excluding it would
    break the addon rather than slim it.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit 14eb27a56fae9aded341f88832527db4e1b71b7d
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 11:31:50 2026 +0530

    Add an automated test harness, and fix what it found

    Three suites behind tests/run-all.sh: luac -p over every file, luacheck,
    and a headless Lua suite of 116 cases. All green.

    The harness is Outfitter's own -- framework, WoW mock, loader and suites.
    It does not vendor the Ka0s testkit, which CLAUDE.md rules out. The mock
    loads the entire TOC and builds hollow frames from the names in
    Outfitter.xml, resolving $parent the way the client's parser does, so a
    file that stops loading is a test failure rather than a surprise in
    someone's client. Nothing rendered is covered; that needs a client.

    Defects the harness found, all fixed here:

    - The Spirit Regen preset never compiled. GenerateSmartUnequipScript
      emitted "delay = 0.5" with no trailing newline, so it ran into the
      next line as "0.5end". Every preset passing an unequip delay was
      affected; Spirit Regen was the only one.

    - The Resting preset declared CATEGORY rather than Category. The reader
      falls back with `Category or Class or "GENERAL"`, so it had been filed
      under General instead of Trade, silently. A new test rejects any preset
      field name that is not one of the five known ones.

    - OutfitterLDB.lua created a global `items` every time the LDB menu
      opened, for want of a `local`.

    - OutfitterBar.lua assigned to two undeclared globals in dead statements.

    - OutfitterInventory.lua computed `local location` twice in one function
      and discarded the second.

    - The zone rebuild renamed three battleground description keys in English
      but left the translations behind in all six locale files.

    Also found and pinned rather than fixed, because the code is retired and
    inert: the CHAMPFACTION preset was never valid Lua. Its condition closes
    with "))) then" against an `if` that opened no parentheses, so activating
    it always raised "Couldn't activate script" -- a defect that predates the
    removed API it was retired for.

    Libraries/MC2DebugLib/MC2DebugLib.lua ships a UTF-8 BOM. The client
    accepts it; luac and Lua 5.1 reject the file outright, so the by-hand
    `luac -p` loop quoted throughout this project was silently skipping it.
    The loader strips it and a test pins the BOM file list.

    luacheck goes from 1601 warnings to 0. Every real finding was fixed at
    source; 587 whitespace-only lines and five trailing-whitespace lines were
    stripped; the rest are house conventions of a 2006-era codebase, listed
    in .luacheckrc by code with the reason rather than a blanket ignore.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit e887c74c724ac79b4655be5248ce05c18dbf0ec6
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 10:59:16 2026 +0530

    Rebuild zone detection on instance map IDs

    GetCurrentZoneIDs matched localized zone names through GetMapNameByID.
    That API is gone, so cZoneSpecialIDMap was commented out years ago and
    every zone-triggered outfit silently stopped firing.

    It now reads GetInstanceInfo: instanceType gives the generic Battleground
    and Arena outfits, so a map added tomorrow still equips them, and the
    instance map ID adds whatever is specific to that map. No localized string
    is on the path any more, which is what rotted the old version.

    cInstanceMapIDZoneIDs covers all 44 battleground and arena map IDs, taken
    from Map.db2 rows with InstanceType 3 and 4 rather than from memory, and
    verified against it: every ID exists and is the right type, and no BG or
    arena in the game is missing. It has to carry the duplicates Blizzard
    created by re-issuing maps -- Arathi Basin is four IDs, Warsong Gulch,
    Eye of the Storm, Deepwind Gorge, Blade's Edge and Nagrand two each.

    The addon's zone tables had also drifted apart before any of this broke.
    Wintergrasp, Sewers, Gilneas and TwinPeaks had presets but no entry in
    cZoneSpecialIDs, so they could never have fired; BladesEdgeArena,
    NagrandArena and LordaeronArena were listed but had no preset. Both lists
    are now reconciled and RingOfValor is dropped, its arena no longer being
    in Map.db2 at all.

    Adds outfits for the maps Outfitter never covered: Silvershard Mines,
    Temple of Kotmogu, Deepwind Gorge, Seething Shore, Deephaul Ravine,
    Ashran, and the twelve current arenas. Brawl maps get a map ID so they
    equip the generic Battleground outfit, but no outfit of their own.

    /outfitter zone reports instance type, map ID and matched zone outfits, so
    a map that does not trigger can be reported as a number.

    City and ArgentDawn stay retired: both are outdoor triggers needing a
    uiMapID list that would go stale every expansion.

    Verified with luac -p and a four-way consistency check over
    cZoneSpecialIDs, cSpecialIDEvents, BuiltinEvents, PresetScripts and the
    map table -- the exact drift described above. Not tested in-client.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit d976df268cef53efa36e84ce966b7b493181ecb7
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 10:46:46 2026 +0530

    Add CLAUDE.md flagging this as non-Ka0s

    Outfitter sits alongside the Ka0s addons but is third-party MIT code forked
    from mundocani's original. The note states it must never join the Ka0s
    roster or audit rotation, that the Ka0s WoW Addon Standard does not govern
    it, and that LibKa0s must never be vendored in.

    Also records what a sweep would otherwise have to rediscover: the mixed
    per-file line endings, the secret-value seam in Compat.lua and the stuck
    EquipmentUpdateCount it causes on error, live preset-script resolution, the
    slot-checkbox strata requirement, and that luac -p is the only verification
    available.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

commit d396f113b1e56e5d7ca76caf99d7c17749f0cbb7
Author: Tushar Saxena <tushar.saxena@gmail.com>
Date:   Wed Sep 16 10:43:34 2026 +0530

    Outfitter 12.1.0.3 for retail (Midnight)

    Community fork of Outfitter by John Stephen (mundocani), MIT licensed.
    Original addon: https://www.curseforge.com/wow/addons/outfitter

    Includes fixes for two reported problems on WoW 12.x:

    - The per-slot checkboxes on the character sheet were invisible.
      OutfitterSlotEnables inherits PaperDollFrame's strata, so another addon
      drawing over the character panel buried them. It is now raised to DIALOG
      in SelectOutfit, not OnLoad, where the frame does not exist yet.

    - PlayerIsFull compared UnitHealth directly, which errors once the client
      returns those as secret values. That abort also left EquipmentUpdateCount
      stuck above zero, which stopped equipment updates firing. Health, power
      and power type now go through OutfitterAPI:UnsecretNumber, as does the
      mana read in UnitHealthOrManaChanged and the item level checks in
      OutfitterItemStats.

    Adds Deprecated.lua, an isolated layer holding functionality the game
    removed. Each retired feature keeps its entry point, which now no-ops via
    Outfitter:DeprecatedFeature; the original code is kept verbatim and
    detached. Retired: void storage transfer, TankPoints, gem capture, the
    spellbook icon set, banked item tooltips, CallCompanionByName, the legacy
    flyout location fallback, the zone-to-outfit map, the HAS_DEBUFF,
    LOW_HEALTH and Championing preset scripts, the Aspect of the Hawk spell
    IDs, and 46 locale strings for mechanics that no longer exist.

    Also fixes WithdrawOutfitFromVoidStorage, which was called from the outfit
    menu but never defined, and TEXT(REPAIR_COST), where only the removed TEXT
    wrapper was at fault.

    README rewritten with credit to the original author and full slash command
    and deprecation documentation.

    Verified with luac -p across every file; not yet tested in-client.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011r9dNiGmVBLVbHQJCrjzbA

This mod has no additional files