!!TOGT-v0.3.0
What's new
Changelog
[v0.3.0] (2026-11-04) - Event stream capture; full error detail (stack and locals)
New Features
- Every event the client fires, captured from the first line of addon code. New
EventStream.lua, loaded right after!TOGT.luain all seven TOCs. One frame callsRegisterAllEventsat file load, so the loading screen and the login are in the stream, which a lettered addon cannot see. Each event becomes one line{ n, pc, e, a }: sequence number,debugprofilestop()milliseconds (notGetTime(), which is frame-locked and would give every event in one frame the same time), event name, and the arguments as text. Strings are quoted, cut at 160 characters and have|doubled; tables and functions show their type; a Retail secret value shows<secret>; past ten arguments it says+N more. The stream is held onTOGToolsEarlyData.eventsin memory only: nothing is saved, so a/reloadstarts a fresh one. It is a ring with a 250,000-line ceiling, oldest dropped first, so a session left capturing stays bounded. Events on the exclude list are counted but not logged. The default list is Blizzard's own/etracefilter (Blizzard_EventTrace.lua:7-23, Classic Era tree) plus events that fire many times a second (COMBAT_LOG_EVENT_UNFILTERED, unit health / power / aura, cooldown updates, cursor and mouseover). TOG Tools' new Event Trace tab reads the stream and setscbto receive each new line live. Requested by the operator on 2026-09-30 ("it needs to be IN !!TOGT so it's captured on startup as the first addon loaded in game"), for reading what the WoW API does, starting with FastGuildInvite's after-login guild-send question (inbox thread15b4d7a3). - The feed is OFF unless switched on, and the switch survives reloads. The operator, 2026-09-30: "it stays off through reload, we don't want a memory leak ... the feed should be off by default". At
PLAYER_LOGINit reads TOG Tools' settings straight fromTOGTools_DB(no dependency, as the inherit probe does) and keeps capturing only when Developer Tools is on andeventTrace.captureis exactlytrue. Anything else, an absent switch included, callsStop(): it unregisters every event and drops what it held.== truematters: AceDB never writes a value equal to its default, so an untouched off switch is absent from the saved variables, notfalse. A saved exclude list is applied at the same moment. Before login the setting cannot be read (TOG Tools' saved variables load after this file runs), so the load itself is always captured and then dropped when the feed is off.Stop()andResume()let the tab's switch apply at once. - Arguments are always renderable text: control bytes and every byte that is not valid UTF-8 are written as
\ddd, and the 160-byte cut never splits a character. AddOn Studio'sEditBox:SetTextpage: "SetText fails when the text contains characters that aren't renderable (e.g. control chars, invalid UTF8). In that case the EditBox is cleared". So one bad byte anywhere blanks TOG Tools' whole Copy box. In game on 2026-09-30, with only control bytes escaped, the box showed at 222 / 804 / 1,208 / 1,691 lines and was blank at 1,992. The cut was by bytes (s:sub(1, 160)), so it could split a multi-byte character, and addon-message payloads carry arbitrary high bytes. Newev.Utf8Safekeeps well-formed UTF-8 (RFC 3629: no overlongs, no surrogates, nothing above U+10FFFF) and escapes everything else; newev.CutUtf8steps the cut back past continuation bytes. Accented names stay readable. Not run in a client: whether this was the cause of the blank box is not established, only that it removes the documented one. 21 new specs inTests/eventstream_spec.lua; line coverage NOT measured, because this repo'sTests/wowapipin predates the harness'scoverage.lua. Locations:EventStream.lua, every.toc,Tests/eventstream_spec.lua. - Blocked / forbidden addon- and macro-action records now carry the call stack. A player asked why Ultimate Tools showed only
[ADDON_ACTION_BLOCKED] AddOn 'Ultimate Guild Roster' tried to call the protected function 'UNKNOWN()'.(Discord, via Ultimate Guild Roster, inbox threadb01704dd). That one line names the addon and the function and nothing about which code path made the call. TheADDON_ACTION_*/MACRO_ACTION_*records now getstack, fromdebugstack(3)inside the event handler (level 3 skips the newactionStackandOnEvent). That is what BugGrabber stores for these events: itsGetErrorStackfalls back todebugstack(3)when there is no error-callstack height (!BugGrabber/BugGrabber.lua:288).debugstackexists in the Forever tree (Blizzard_ScriptErrors.lua:56). The call is wrapped in apcalland nothing is stored when it throws, returns a non-string, or (Retail) returns a secret value;issecretvalueis feature-detected. Lua warnings, Lua errors andSAVED_VARIABLES_TOO_LARGEtake no stack. TOG Tools v0.13.0 stores the stack and shows it under the line in its Explain window. An older TOG Tools ignores the field. Seen in game on WoW Forever (operator, 2026-11-04: "confirmed it's all there"): a forbiddenInvite()recorded the stack from this handler (!TOGT.lua:155) down through[C]: in function 'Invite'to the calling addon's own file and line. Not yet seen: anUNKNOWN()block. Three new specs.debugstackandissecretvaluewere added to.luacheckrcand.luarc.json. Locations:!TOGT.lua,Tests/earlydata_spec.lua,.luacheckrc,.luarc.json. - Every Lua error and blocked action now carries its stack AND its locals, the full detail BugSack shows. The operator, 2026-11-04: "why don't we have the full detail?". The new
errorDetail()replacesactionStack, and both the error handler and the action events call it. Inside an error handler the level is Blizzard'sGetErrorDataarithmetic (Blizzard_ScriptErrors.lua:48-64, Classic Era and Forever trees):GetCallstackHeight() - (GetErrorCallstackHeight() - 1). Outside one it is 3.debuglocals(level, true)skips functions and userdata as Blizzard does.|k/|Kbecome plain letters (Blizzard'sRemoveKStrings) and secret values are dropped. Every API is feature-detected. Blizzard's pre-handler snapshot (ScriptErrors:GetUnhandledErrors) also gives up itsstackandlocalsnow. Fixes my first cut:pcall(debugstack, 3)counted thepcallas a frame, so the in-game stack started on this addon's own handler (!TOGT.lua:155) rather than at[C]: in function 'Invite'.debugstackanddebuglocalsare now called directly; neither throws on a number. The four action events share one branch (ACTION_VERB), so each one callserrorDetailstraight fromOnEvent, as its level 3 requires. Seven specs replace the three stack-only ones.debuglocals,GetCallstackHeightandGetErrorCallstackHeightwere added to.luacheckrcand.luarc.json. Not yet seen in game. Locations:!TOGT.lua,Tests/earlydata_spec.lua,.luacheckrc,.luarc.json.
Improvements
- Version and docs. This work was in progress as v0.2.5 and was never tagged, so it ships as v0.3.0: it adds two features. The CurseForge page and README now describe the full error detail and the event feed and call the parent addon Ultimate Tools. The CurseForge page's two links to the Ultimate Tools project page are plain text now, because these projects allow Discord links only (TOGTools' description checker failed the page on both). Locations:
docs/Curseforge_Description.html,README.md. wow-version-replication.ps1now replicates into WoW Forever's new_forever_install folder. In game on Forever (2026-11-04), the operator still saw only the one-line blocked-action error, because the_forever_copy of!TOGT.luawas the old one: the script listed only_classic_beta_._forever_is added, and_classic_beta_stays while it is installed. After a restart the watcher copied the new!TOGT.luathere. Dev-only; the script does not ship. Location:wow-version-replication.ps1.
[v0.2.4] (2026-09-27) - Startup check of XML handler inherit order
New Features
- Startup probe: which order
inherit="prepend"/inherit="append"OnLoad handlers run in. Requested by WoWAPITesting (inbox thread3f630561): the harness runs a prepend handler BEFORE the template's own OnLoad and an append handler AFTER it, on the strength of two web-search summaries only, and ClassicCalendar's specs depend on that order.TOGTInheritProbe.xmlis the harness'sconformance/PrependOrderProbe(c936c1d) renamed: one virtual template whose OnLoad appends"inherited"toself.order, and two frames inheriting it with<OnLoad inherit="prepend">/inherit="append".!TOGT.luareads both frames at the firstPLAYER_ENTERING_WORLD(the chat frame is not ready at load), stores the joined orders inTOGToolsEarlyData.inheritOrder, and prints!!TOGT inherit order -- prepend: .../-- append: ...only while TOG Tools' "Verbose debug output" is on. That switch is read straight fromTOGTools_DB.global.debug, so there is still no dependency, and a player without it sees nothing. Expected if the harness is right:prepend, inheritedandinherited, append. A missing frame readsnot loadedrather than erroring. Added to all seven TOCs after!TOGT.lua. Five new specs pin the reporter; the XML order itself is not testable offline, because it is exactly the thing being measured. Not run in a client. Locations:TOGTInheritProbe.xml,!TOGT.lua, every.toc,Tests/earlydata_spec.lua.
Improvements
A
.luacheckrc, which the repository never had. Without one luacheck flagged every WoW global in!TOGT.luaas undefined. The read-only globals mirror.luarc.json's list,TOGToolsEarlyDatais the one global the addon owns, andTestsgets the fleet'slua51+bustedblock.DEFAULT_CHAT_FRAMEadded to.luarc.jsonfor the probe. Locations:.luacheckrc,.luarc.json.wow-version-replication.ps1now replicates into WoW Forever._classic_beta_(Battle.net productwow_classic_beta) added to the version list, and a destination is now kept when the VERSION folder exists rather than when itsInterface\AddOnsfolder does: a freshly installed client has no AddOns folder yet, so the old test skipped Forever silently even once it was listed. The AddOns folder is created along with the addon folder. Dev-only; the script does not ship. Location:wow-version-replication.ps1.Addon-list title's version tag in grey, and closed, on all seven TOCs. Fleet request
ff41f4c4(DeltaSync, at the operator's direction). The tag used|c999999FF, which is alpha-first (a pale blue, not grey), and was never closed; it is now|cff999999<Version>|rafter the already-closed orange name. The Cata TOC's tag now readsCataclysm, the fleet's word for it. Not yet seen in the client's AddOns list. Locations: every.toc.
[v0.2.3] (2026-09-20) - WoW Forever support
New Features
!!TOGT_Camelot.tocfor WoW Forever -- Forever (Battle.net productwow_classic_beta, codename Camelot) is the retail client with vanilla content at## Interface: 16001; the client reads<Addon>_Camelot.tocbefore<Addon>_Mainline.tocand falls back to the plain!!TOGT.toc, whose Interface list does not carry 16001. So on Forever!!TOGTloaded only with "Load out of date AddOns" ticked, and TOG Tools (## Dependencies: Ace3, GuildRoster, !!TOGT) failed withFailed to load missing dependency [!!TOGT]-- the same failure mode as the v0.2.1 / v0.2.2 Interface bumps, for a flavour rather than a build. The new manifest is!!TOGT_Mainline.tocwith the Interface line and Title changed.!TOGT.luabranches on nothing flavour-specific, so the TOC is the whole change. Requested by TOGTools (inbox thread0a9abbb39cb5), which shipsTOGTools_Camelot.tocin its v0.8.8; the recipe is FastGuildInvite's (thread7480082e), who confirmed the packager and CurseForge accept 16001. Not verified in a Forever client -- none exists on this box. Location:!!TOGT_Camelot.toc.
Bug Fixes
!!TOGT_BCC.tocrenamed to!!TOGT_TBC.toc-- the old name was one no client reads, so TBC Classic and Classic Anniversary loaded the Vanilla manifest. Peer-review finding 1 (2026-08-07,docs/AUDIT.md), confirmed against the TOC format page: modern suffixes take an underscore (_TBC), the only legacy hyphen forms were-BCC/-WOTLKC, and-BCCwas dropped in Anniversary 2.5.5._BCCwas neither, so those clients fell through to!!TOGT.toc(## Interface: 11509), which they mark out of date -- and then TOG Tools (## Dependencies: ... !!TOGT) fails to load on them unless "Load out of date AddOns" is on. The same failure mode as every Interface bump in this changelog, caused by a filename rather than a number, and present since the file was created. The20506inside it was already right and is unchanged. Location:!!TOGT_TBC.toc(git rename).wow-version-replication.ps1replicatedTests\,docs\and every dotfile into the other WoW installs. Peer-review finding 2 (2026-08-14). Two defects, both measured with-DryRunbefore and after: (1) a bare folder name from.pkgmetacompiled to^Tests$, which matches only a file of that name -- the packager forbids the trailing slash the script keyed on, so a correct.pkgmetawas exactly what broke it; a wildcard-free entry naming a directory in the repo is now promoted to the prefix form, the fix seven other scripts in the fleet already carry. (2) The always-skip list named.git,.gitignore,.gitattributesand.gitmodulesindividually, so.busted,.luarc.json,.markdownlint*,.claude\,.github\and.vscode\all copied; one(^|\\)\.pattern now skips every dot component, which is what the packager does. After the fix the dry run's WOULD list is the release zip exactly: the seven TOCs,!TOGT.lua,CHANGELOG.md,LICENSE,README.md. Location:wow-version-replication.ps1.
Improvements
docs/AUDIT.mdretired. The peer-review board is superseded by writ's inbox; its two open findings are the two fixes above, so nothing was left to import. The file is deleted rather than kept, per the fleet rule (an empty board reads as a board nobody has looked at); the findings' full text is in git history atd879a2e.CLAUDE.md's tag note corrected from_TOGT-vX.Y.Zto the!!TOGT-vX.Y.Zform every tag since v0.2.0 actually uses. Locations:docs/AUDIT.md(deleted),CLAUDE.md.
Documentation
- A
README.md, which the repository never had. Written from the CurseForge description and checked against the manifests: no SavedVariables line in any TOC (so "no saved data" is true), no## Dependencies(so "no dependencies of its own" is true), and TOG Tools' hard dependency on it stated from TOG Tools' side. The CurseForge description's supported-versions line now names Forever. Locations:README.md,docs/Curseforge_Description.html.
[v0.2.2] (2026-07-31) - Classic Era & Mists compatibility, offline test suite
Bug Fixes
!!TOGT marked out-of-date on current Classic Era and Mists —
!!TOGT.tocdeclared## Interface: 11508and!!TOGT_Mists.tocdeclared50503, while the live clients are on11509and50504. Clients on those builds see!!TOGTas incompatible and skip it unless "Load out of date AddOns" is ticked, which then breaks TOG Tools (## Dependencies: Ace3, VersionCheck-1.0, !!TOGT) withAddOn [TOGTools] Failed to load missing dependency [!!TOGT]even for users who have!!TOGTinstalled. Same failure mode as the TBC bump in v0.2.1 and the Retail Midnight bump in v0.1.1. Both## Interface:and## X-Min-Interface:bumped in each file, matching the values already carried by LibGuildRoster, LibItemDB and LibProfessionDB. Locations:!!TOGT.toc,!!TOGT_Mists.toc.Comments inside the
.pkgmetaignore:list — Four comment lines sat between entries in the ignore block. The packager'syaml_listitem()trims only a leading-, whitespace and one leading/trailing quote — it does not strip comments — so anything the parser takes from inside that block is treated as a pattern rather than a note. The canonical form keeps the list free of comments entirely; all commentary moved above theignore:key, with the rule added to the file's own header so it is visible locally rather than depending on a global copy. No entry values changed. Location:.pkgmeta.
Improvements
Offline unit-test suite with verified 100% line coverage —
Tests/earlydata_spec.luanow runs 20 tests covering!TOGT.luaend to end: record shapes for every captured event, the ring-cap buffer keeping the newest records and counting what it dropped, the handoff from buffering to TOG Tools' live callback, the error-handler wrap and its tail-call to the previously installed handler, re-claiming the top spot after !BugGrabber replaces it, refusing to wrap itself twice, Retail's pre-handler error-snapshot drain including the case where that API throws,ADDON_LOADEDordering and offsets,PLAYER_LOGINteardown, and the duplicate-copy idempotency guard.Coverage is measured, not asserted:
Tests/coverage.luaderives the executable-line set from the Lua 5.1 bytecode debug info (walking each prototype'slineinfoand excluding jump-only lines) rather than guessing from source text, so the denominator is real. 76/76 executable lines, 100.00%.Four specs were added to reach it. The gap was the
MACRO_ACTION_FORBIDDENbranch, uncovered because the suite exercised only itsMACRO_ACTION_BLOCKEDtwin — blocked and forbidden are different severities arriving on separate events, so a mislabel there misreports which protection tripped. Also added: a sweep firing every registered event with no payload at all. Line coverage never reaches theor "?"/or ""side of those fallbacks, and this handler is the entire capture path — one uncaught throw in it and the addon silently stops recording for the rest of the session.No CI test workflow —
.github/workflows/tests.ymlwas removed. It ran the suite on a GitHub-hosted runner on every push and PR; the suite is run locally, by hand, with zero dependencies (lua Tests\wowapi\run.lua). With one developer and no second contributor a green check on GitHub adds nothing and isn't visible where the work happens — a failing test needs to stop the change locally, before it lands.release.yml(packaging) is untouched.CLAUDE.mdgained a## Test system: runnerless, local onlysection so a later session doesn't reinstate it or go hunting forbusted, which is not the runner.
[v0.2.1] (2026-07-17) - TBC Classic Compatibility
Bug Fixes
!!TOGT marked out-of-date on current TBC Classic —
!!TOGT_BCC.tocdeclared## Interface: 20505while the live TBC Classic client is on build20506. Clients on that build saw!!TOGTas incompatible and skipped it (unless "Load out of date AddOns" was ticked), which in turn broke TOG Tools (## Dependencies: Ace3, VersionCheck-1.0, !!TOGT) with8x LUA_WARNING: AddOn [TOGTools] Failed to load missing dependency [!!TOGT]— even for users who had!!TOGTinstalled. Fix: bumped both## Interface:and## X-Min-Interface:to20506to match the current TBC Classic build andTOGTools_BCC.toc. Same failure mode and fix as the Retail Midnight bump in v0.1.1. Location:!!TOGT_BCC.toc.BigWigs packager couldn't find the TOC (release failed) —
.pkgmetastill declaredpackage-as: !TOGT, the pre-rename name; after the v0.2.0!TOGT→!!TOGTrename the TOC files are!!TOGT.toc/!!TOGT_<flavor>.toc, so the packager searched for!TOGT.toc, found nothing, and aborted with "Could not find an addon TOC file." (The v0.2.0 CurseForge release failed the same way —package-aswas never updated after the rename.) Fix:package-as: !!TOGT. Location:.pkgmeta.
[v0.2.0] (2026-06-11) - Renamed to !!TOGT (loads first) + early diagnostics capture
New Features
Renamed
!TOGT→!!TOGTso it loads first. WoW loads addons alphabetically by folder name;!!TOGTsorts ahead of every other addon — crucially before!BugGrabber. That ordering is what lets it grab the realseterrorhandlerbefore BugGrabber neuters it, which makes the error capture below coexist with BugSack (see the wrap). Upgrading from!TOGT: the CurseForge app replaces the folder automatically; manual installers should delete any leftover old!TOGTfolder so a stale duplicate doesn't load alongside!!TOGT. No SavedVariables, so nothing to migrate.Diagnostics capture for TOG Tools — Alongside ADDON_LOADED timing,
!!TOGTnow captures from the very first moment of load: Lua errors, Lua warnings (LUA_WARNING), blocked/forbidden addon-action events (ADDON_ACTION_BLOCKED/_FORBIDDEN+ theMACRO_variants), andSAVED_VARIABLES_TOO_LARGE(silent saved-data loss). Acapture()function buffers records intoTOGToolsEarlyData.diagnostics(ring-capped at 250, with adroppedoverflow counter) until TOG Tools sets.cb, after which records stream straight over. A dedicated event frame (NOT unregistered atPLAYER_LOGIN, so it captures all session) handles the events; the action / SV records are pre-formatted (source= culprit,detail= the reason) and recorded by TOG Tools as errors — they are NOT "taint" (true taint propagation goes only to the unreadable on-disk taint.log). Lua errors/warnings keep the raw message so TOG Tools owns thepath:line: reasonparsing. New globalstime/geterrorhandler/seterrorhandlerin.luarc.json. Still no SavedVariables. Consumed by TOG Tools v0.7.0+ (Diagnostics tab).Good-citizen error-handler wrap (coexists with BugGrabber/BugSack) — BugGrabber loads after us, REPLACES the error handler without chaining, then neuters the global
seterrorhandlerso nothing else can register. Because!!TOGTloads first, it saves the realseterrorhandlerup front and re-asserts itself on top (on eachADDON_LOADEDand atPLAYER_LOGIN) whenever the active handler isn't ours. Our handler captures the error, then tail-calls the previous handler (return prev(msg)) — in Lua 5.1 a tail call drops our own frame, so the wrapped handler (BugGrabber's grabError, or Blizzard's default) sees a clean stack and runs exactly as if it were on top. Net result: TOG Tools and BugSack both capture every Lua error, with no breakage to either. (Aprev == ourHandlerguard prevents wrapping ourselves.)Retail: back-fill the pre-load error buffer — On Retail, Blizzard's modern pipeline (
Blizzard_ScriptErrors, loaded before any addon) buffers errors that fired before any handler registered intoScriptErrors.unhandledErrors.!!TOGTdrains that snapshot once at load to pick up errors from core UI load that happened before even!!TOGT. Read-only (not cleared, so Blizzard's own error frame still gets them); does NOT useAddLuaErrorHandler(it assertsissecure()and fails from addon code). Feature-detected via theScriptErrorsglobal → a no-op on Classic Era. New globalScriptErrorsin.luarc.json.Idempotent init —
TOGToolsEarlyDatais initialized with a guard (= or {}plus an__togtInitflag), so a stray duplicate copy of the addon can't clobber the table the first copy populated or double-register handlers.
[v0.1.1] (2026-05-23) - Retail Midnight Compatibility
Bug Fixes
- !TOGT marked out-of-date on current Retail (Midnight 12.0.x patches) —
!TOGT_Mainline.tocdeclared## Interface: 110207(the TWW-final build); live Retail is on Midnight 12.0.5 and 12.0.7. Clients on those builds saw !TOGT as incompatible, which in turn broke TOGTools (## Dependencies: Ace3, !TOGT) for any user without "Load out of date AddOns" ticked. Fix: expanded to## Interface: 110207, 120000, 120001, 120005, 120007to cover both the final TWW build and the entire current Midnight patch range. Verified against currently maintained Retail addons (RaiderIO120000-120005, !BugGrabber up to120007, Bagnon120005, Ace3120000-120001). Location:!TOGT_Mainline.toc.
Improvements
- Stripped non-standard TOC fields —
!TOGT_Mainline.toccarried## Interface-Retail:,## Interface-Classic:, and## Interface-BCC:lines that look like multi-flavor selectors but are not recognised TOC fields — the WoW client silently ignores them, and the BigWigs packager produces per-flavor TOCs from.pkgmetadirectives rather than from in-TOC selectors. Removed to avoid future confusion. Location:!TOGT_Mainline.toc.
[v0.1.0] (2026-05-04) - Sub-Millisecond Timing & CurseForge Wiring
Bug Fixes
- Per-addon load times collapsed to
0.000s—GetTime()is frame-locked, so everyADDON_LOADEDevent fired in the same loading-screen frame returned the same timestamp; the per-addon deltas TOG Tools computed from the offsets all came out as zero. Switched the capture in!TOGT.luatodebugprofilestop()(sub-millisecond precision); offsets are still stored in seconds (ms / 1000) so theTOGToolsEarlyDataconsumer contract is unchanged.
Improvements
- CurseForge project ID set —
1533953populated in all six TOC files (!TOGT.toc,!TOGT_BCC.toc,!TOGT_Wrath.toc,!TOGT_Cata.toc,!TOGT_Mists.toc,!TOGT_Mainline.toc) and.pkgmeta(replacing thePLACEHOLDERfrom initial release), so the BigWigs packager can publish to the correct CurseForge project. - CurseForge user-facing description — Added
docs/Curseforge_Description.htmldescribing what the companion does, why it's needed, and how to use it alongside TOG Tools. .luarc.jsonupdated — Addeddebugprofilestoptodiagnostics.globalsso the new timer call resolves cleanly under the Lua LSP.
[v0.0.1] (2026-05-04) - Initial Release
New Features
- Load timer companion — Registers for
ADDON_LOADEDfrom the very first frame of the loading screen. Records load order and time offset (seconds since first addon loaded) for every addon. Stores results in theTOGToolsEarlyDataglobal for TOG Tools to read and display in the Addon Load tab. - Login window tracking — Records total time from first
ADDON_LOADEDtoPLAYER_LOGINas the overall loading screen duration. - All WoW versions — TOC files for Vanilla (11508), TBC (20505), Wrath (30405), Cata (40402), Mists (50503), and Retail (110207).
All Relations
- All Relations
- Embedded Library
- Optional Dependency
- Required Dependency
- Tool
- Incompatible
- Include
This mod has no related projects

