Skip to content

Eight live fixes: profile switches, the dispel ring, a fatal GetChildren, Max Debuffs, retargets, the removed item globals, the RES icon, and a stranded visibility latch - #261

Merged
DanderBot merged 7 commits into
DanderBot:mainfrom
Krathe82:krathe/live-5.3.1-fixes
Sep 11, 2026

Conversation

@Krathe82

@Krathe82 Krathe82 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Eight fixes on top of the ported aura-container work. Seven are from live 5.3.1 reports; the eighth (§8) is a regression in this branch's own lineage, found in the field tonight. Independent of each other, so they can be taken separately if any one is contentious.

⚠ Rebased onto current main on 2026-09-07 — the branch had drifted 39 commits behind.


1 · A profile switch could be aborted part-way through

"script ran too long", through SyncFrameUpdateAurasIterateRaidFramesUpdateAllAurasFullProfileRefreshApplyRuntimeProfile — i.e. an auto-profile switch.

Run synchronously, UpdateAllAuras walks every party, raid and pinned frame and rebuilds the whole Aura Designer signature set for each — placedCoSig/placedStructSig per indicator per member group, all string-built. On a full raid with a busy Aura Designer profile that is enough to trip the watchdog, and the watchdog aborts rather than warns: everything in FullProfileRefresh after that call never ran, so a profile switch could half-apply and leave frames stale with nothing to re-drive them.

The watchdog measures a single execution, so splitting the walk across frames removes the failure rather than making it less likely. Snapshot the work list up front (the iterators walk registries that churn), re-validate each frame at execution time, generation token so a newer call supersedes a pending one — the same shape as _kickLiveParse. The first chunk runs inline, so a 5-man is one chunk and behaves exactly as before.

⚠ Not a regression from the ported work: every function in the reported stack was last touched between 10 July and 12 August.

2 · The dispel colour ring ignored Show Border

All borders disabled, yet every dispellable debuff still had a coloured ring — green on poison, brown on bleed.

debuffBorderColorByType was read on its own with no reference to debuffShowBorder. Worse, the by-type checkbox lives inside the Border section, so with borders off the user could not reach it to untick — their only escape was to re-enable the border, untick by-type, and disable the border again.

The ring is border art, so it now answers to debuffShowBorder.

⚠ The colourblind symbol stays ungated on purpose: it is text, not border art, and shipped decoupled deliberately — someone running without borders should still get it.

3 · An unguarded GetChildren killed click-casting recovery

Reported 126× in one session:

bad argument #1 to '?' (Attempt to access forbidden object from code tainted by an
AddOn - Usage: local (scriptObject)* = self:GetChildren())
ClickCasting/Frames.lua:1338 in function 'PropagateMouseOnChildren'

frame:GetChildren() was the one call in that function not guarded, while the comment directly beneath it promised everything there was. The guard above it tests that the method exists, which says nothing about whether calling it is permitted — GetChildren refuses to hand forbidden children to tainted code and throws doing it.

The existing IsForbidden check cannot prevent this: a child passes it and can still have forbidden children of its own, so the throw lands one level down, on the recursion.

Per that function's own note, a throw there does not skip one child — it abandons the PLAYER_ENTERING_WORLD settle callback and takes ApplyGlobalBindings, RunBindingRepair("zone-in") and ResolveColdStartProfile with it. So click-casting recovery was failing on every zone-in that touched those frames.

4 · Max Debuffs did not mean what it says

"Despite having set it to a maximum of 3 it shows 4 or more", on Show All with stock settings.

Confirmed, and it is an engine limit rather than a bug in the row: maxFrameCount is per aura group and there is no container-level total (Blizzard_AuraContainerGroupsmaxFrameCount is group state, nothing sums across groups). A row split into N records can therefore render up to N × max. The Important Debuffs highlight splits Show All into three groups and is on by default, so the stock configuration already carries a 3× ceiling; category mode reaches five or six.

It cannot be budgeted away. Sharing one allowance would need to know how many auras each group will match, and the Show All records are separated only by candidate booleans (isBossOrRoleAura / isPriorityAura) which C_UnitAuras.GetUnitAuraInstanceIDs cannot evaluate — all three carry the same filter string, so a count returns the same number for each. Dividing blindly under-shows the common case (a unit with only ordinary debuffs would get max/3), and collapsing the split to make the number true silently deletes the highlight.

Neither trade is acceptable — losing debuffs or losing a feature to make a label honest is worse than the label. So it says so instead. DF:GetDebuffRowGroupCount reports the worst case from settings alone (Aura Designer claims only ever remove records, so ignoring them is the right direction for a ceiling), and the slider carries a note:

Note: The game applies this limit to each category separately. Your filters use 3 categories, so up to 9 debuffs can show at once.

It stays silent at one group, where the number means exactly what it says.

Implementation notes: hideOn for visibility and refreshContent for the text, because RefreshChildStates only calls refreshContent on a shown widget — hiding from inside it would freeze the note hidden. Refresh goes through tools2.refreshStates rather than the page's, since that group is also built into a popout.

5 · A refused retarget desynced the container permanently

"happens every time I join raid, to fix have to reload after everyone has joined" — an indicator drawn on a player who never had that aura, and not lighting for the player who did. Only while the raid is forming; a reload clears it.

Two places wrote the new unit before calling SetUnit and ignored the result. SetSlotOwnerUnit guards on owner.unit == unit at the top, so an optimistic write turns any refusal into a permanent desync: the owner reads as retargeted, every later call short-circuits, and the container stays bound to the previous occupant until a reload. The regen drain had it worse — it clears pendingUnit and drops the owner from the registry first, so a refusal lost the retarget outright.

Both now commit only on success. On failure the old token is left in place, which is what the combat branch already documented (owner.unit is left on the OLD token deliberately, so GetUnit stays truthful and a repeat call simply re-queues); the out-of-combat path was the one place not honouring its own contract. The drain re-queues after the loop, never inside it — adding a key during a pairs() traversal is not legal, only nil-ing an existing one is.

It also reads the engine back. AuraContainerSharedMixin:GetUnit returns a plain string, not a secret, so "did the retarget land" is directly answerable and was simply never asked. A mismatch is reported, not repaired: the unit is already committed and SetUnit no-ops when its own token matches, so the cure would be a rebuild.

⚠ Candidate fix plus a detector, not a confirmed diagnosis. SetUnit is plain mixin state and rarely refuses, so these may be latent rather than the reported cause. The read-back is the part that settles it: if this recurs, the log names the wrong unit instead of leaving it looking like a filter fault.

6 · Two item globals that 12.1.5 removes

GetItemSpell and GetItemCount live in Blizzard_DeprecatedItemScript, which 12.1.5 removes outright. Both are exact 1:1 forwards to C_Item, and both are already dead for anyone running without loadDeprecationFallbacks — so the item pickers in CC:GetSlotItemInfo and CC:GetItemInfoById could error on a nil global today, not only after the patch.

CC:GetItemCount fell back to the alias of the very function it had just called, so that fallback is dropped rather than renamed.

7 · The resurrection icon could miss its only update

"It has happened twice this week… I could see the res light on the corpse and they could take the res, but the RES text didn't show", in M+ and in raid.

This is the one status icon where a single missed update is permanent:

  • INCOMING_RESURRECT_CHANGED is its only show driver. The "pending accept" (yellow) state is derived from having previously observed the cast (resCache[unit] == 1), so a frame that never saw the casting edge can reach neither state and falls through to Hide().
  • ResTimerCleanup only ever hides. It never discovers.
  • The only recovery is UpdateAllStatusIcons, reachable from a full-frame refresh or a combat transition. Inside an M+ pull or a boss fight neither happens — so a missed update lasts the whole fight, which is the envelope every report describes.

And it was the only status icon routing that update through a single unitFrameMap[arg1] lookup. The payload is typed UnitTokenVariant, so the token delivered is not guaranteed to be the token the map is keyed by.

The client's own CompactUnitFrame registers this event with a plain RegisterEvent and refreshes each frame without reading the payload at all. This mirrors that: walk all frames, plus a separate pinned walk since IterateAllFrames has no pinned arm. The event fires when a resurrection starts or stops on a group member, not on a timer, so the sweep is affordable.

⚠ This removes the class of failure, not a confirmed trigger — the miss has not been reproduced in game and the change does not claim to name it. Two threads stay open and are not addressed here: whether an instant battle rez presents an observable casting edge at all, and that GetStatusIconFadeAlpha multiplies this icon by fadeDeadIcons — an icon which by definition only ever exists on a dead unit.


8 · A stranded visibility latch blanked every Aura Designer icon until a reload

Field, 2026-09-07: joined a raid from player housing; every Aura Designer icon vanished — including on the reporter's own frame — and did not return until /reload. Three faults, all in the visibility latch.

The self-exemption was a state test, and it raced. The edge gated on UnitIsUnit(unit, "player"). One second after a reload, with the roster still building, that answers false for your own raidN token while UnitExists is already true and UnitIsVisible already false — so the branch ran on the player and latched him:

19:19:57  --- UI Reload ---
19:19:58  visibility latch ON unit=raid9      <- his own token

It now requires the identity to have resolved — two GUIDs that both read back as plain strings. Anything else (nil during roster build, a secret under identity restriction, a pcall failure) leaves the unit shown, which is this latch's standing fail-safe rule.

The verdict was stored in the container, and containers are retargeted. This is what made it permanent. The registry is keyed by UNIT; the actuation was keyed by whichever container pointed at that unit at that instant. So SetUnitVisibilityLatched(unit, nil) could not reach a container that had since moved — and Handle:SetUnit then re-seeded it from its new unit, which during a raid join is very likely also latched.

19:20:12  debuff:    retarget raid8 -> raid9
19:20:16  defensive: retarget raid9 -> raid8
19:20:18  defensive: retarget raid8 -> raid9
19:20:32  raid2->raid1, raid3->raid2, raid4->raid3, raid5->raid4 ...

Nothing could recover it: ReconcileLatches walks the registry and calls the same unit-scoped function, and the drift check only ever warned in the leak direction. A reload worked because it discards every handle.

Nothing stores the verdict now — every actuation asks the registry for the unit it is bound to right now, and _visLatched survives only as a memo of the last application. Both _setVisLatch setters ignore their argument and recompute, so every existing caller became correct without a call-site change and none can poison a handle by reasoning about the wrong unit. ReconcileLatches additionally re-asks every handle and slot (idempotent — a container that agrees returns on the memo check) and warns when it finds one held dark for a unit that is not latched. That direction had no detector at all, which is why the log showed nothing.

⚠ This is the converse of the August death-latch fix, which established that an actuation keyed by UNIT needs an edge keyed by UNIT. The half never checked was that an edge keyed by UNIT needs an actuation keyed by UNIT.

It darkened pools the leak cannot reach. The guard exists for the PLAYER filter token failing open, which can only affect pools whose filter names PLAYER. In the reported session, 2 of 10 container filters were source-relative and all 10 were darkened. Both halves come out of the same log: the PLAYER-token partition broke 5 times and every one carried vis=0, while the same probe ran 32 times at vis=1 without a break; and 17 raid units latched in a single tick while their containers still reported live helpful counts (one held 8 buffs throughout). The trigger is real; the scope was not. The actuation now gates on _idGateSourceRelative — a flag this file already computed in five places and read in none outside the debug dump.

This overrules a documented 2026-08-18 decision, deliberately and at the maintainer's direction. That note said every pool on a unit outside your world is stale, not just source-relative ones, and that narrowing once left a cross-instance unit showing a stale debuff row. It is not retracted — the comment above SetUnitVisibilityLatched now carries both sides and names the single switch to reverse it. What changed is the price: UnitIsVisible goes false for out-of-render-range group members, not only cross-instance ones, so the blanket response fires constantly in a raid.

The death latch is untouched and keeps its per-unit blanket scope: death really does freeze every pool, with no aura event to follow.

Confirmed in the field after the fix. The same event class — a 27-unit mass latch on a zone transition in a 25-man raid — cleared 14 units within one second and the rest within two minutes, with no reload. Session ledger went from 65 ON / 7 OFF to 45 ON / 41 OFF, the new blanking detector never fired in 3,963 entries, and the player's own token never latched once.

Verification

All changed files parse; no new globals; no line endings changed against main; the toc is untouched.

Fixes 2, 3, 6 and 7 are reproduced from the reports and from source rather than measured in game — 2 is a missing condition, 3 an unguarded call, 6 a removed global, 7 a missing recovery path, all readable from the source. Fix 1 reproduces a reported stack. Fix 4's engine limit is checked against the client's own AuraContainerGroups. Fix 8 is diagnosed from the reporter's own debug trail and confirmed in the field after the change — it is the only one here measured on both sides. Fixes 5 and 7 are explicitly candidate fixes and say so in their commit messages; both add a detector or remove a failure class rather than claiming a proven trigger.

@Krathe82 Krathe82 changed the title Four live 5.3.1 fixes: aborted profile switches, the dispel ring, a fatal GetChildren, and Max Debuffs Seven live 5.3.1 fixes: profile switches, the dispel ring, a fatal GetChildren, Max Debuffs, retargets, the removed item globals, and the RES icon Sep 7, 2026
… mid-apply

Field report: "Factory.lua:890 script ran too long", through SyncFrame ->
UpdateAuras -> IterateRaidFrames -> UpdateAllAuras -> FullProfileRefresh
-> ApplyRuntimeProfile, i.e. an auto-profile switch.

Run synchronously this walks every party, raid and pinned frame and
rebuilds the whole Aura Designer signature set for each -- placedCoSig
and placedStructSig per indicator per member group, all string-built. On
a full raid with a busy Aura Designer profile that is enough to trip
Blizzard's watchdog, and the watchdog does not warn, it ABORTS the
execution. Everything in FullProfileRefresh after this call never ran, so
a profile switch could half-apply and leave frames stale with nothing to
re-drive them.

The watchdog measures a single execution, so splitting the walk across
frames removes the failure rather than making it less likely. Same shape
as AuraContainer._kickLiveParse: snapshot the work list up front because
the iterators walk registries that churn, re-validate each frame at
execution time, and use a generation token so a newer call supersedes a
pending one instead of two walks interleaving. The first chunk runs
inline, so a 5-man is one chunk and behaves exactly as before.

Not a regression from the current aura work: every function in the
reported stack was last touched between 10 July and 12 August, and none
of today's Factory changes are in that chain.

(cherry picked from commit 8bc2288b656d2f6d53466dc93403ca6eee7d794c)
(cherry picked from commit 10f36a085339b64da406fa7c302490384ca9542d)
…atal unguarded GetChildren

Dispel colour ring (undee): the by-type flag was read on its own, so a
user with Show Border OFF still got a coloured ring on every dispellable
debuff, with no reachable setting to turn it off -- the by-type checkbox
lives inside the Border section and is out of reach while that section is
off. Their only escape was to re-enable the border, untick by-type, and
disable the border again. The ring is border art, so it now obeys
debuffShowBorder. The colourblind SYMBOL stays ungated on purpose: it is
text, not border art, and shipped decoupled deliberately.

PropagateMouseOnChildren (mist, 126x in one session): frame:GetChildren()
was the one call in that function not pcall'd, while the comment directly
under it promised "everything here is pcall'd". The guard above tests
that the METHOD EXISTS, which says nothing about whether calling it is
permitted -- GetChildren refuses to hand forbidden children to tainted
code and throws doing it. The IsForbidden check cannot prevent this: a
child passes it and can still have forbidden children of its own, so the
throw lands one level down on the recursion.

Per that function's own note, a throw there does not skip one child, it
abandons the PLAYER_ENTERING_WORLD settle callback and takes
ApplyGlobalBindings, RunBindingRepair("zone-in") and
ResolveColdStartProfile with it -- so click-casting recovery was failing
on every zone-in that touched those frames.

Both parse clean, ENV-SAME, CRLF intact.

(cherry picked from commit 562b85c1792865bfadc3ebb481acc493ae977860)
…king it

Reported as "set it to a maximum of 3, it shows 4 or more" on Show All
with stock settings. Confirmed: Blizzard caps at maxFrameCount PER AURA
GROUP and the engine has no container-level total, so a row split into N
records renders up to N x max. The Important Debuffs highlight splits
Show All into three groups and is ON BY DEFAULT, so the stock config
already has a 3x ceiling; category mode reaches five or six.

It cannot be budgeted away. Sharing one allowance would need to know how
many auras each group will match, and the Show All records are separated
only by candidate BOOLEANS which GetUnitAuraInstanceIDs cannot evaluate --
all three carry the same filter string, so a count returns the same
number for each. Dividing blindly under-shows the common case, and
collapsing the split to make the number true silently deletes the
highlight.

Krathe's call: never lose debuffs or functionality, so state the real
ceiling. DF:GetDebuffRowGroupCount reports the worst case from settings
alone (claims only ever remove records), and the Max Debuffs slider now
carries a note giving the category count and the resulting maximum. It
stays silent at one group, where the number means exactly what it says.

hideOn for visibility and refreshContent for the text, because
RefreshChildStates only calls refreshContent on a shown widget -- hiding
from inside it would have frozen the note hidden. Refresh goes through
tools2.refreshStates, not self:RefreshStates, since this group is also
built into a popout.

(cherry picked from commit c93a47b31bba4507a3848635d57316f94c0e1676)
…inding back

Report, still present on v5.4.0-alpha.3: "happens every time I join raid,
to fix have to reload after everyone has joined" -- Earth Shield drawn on
a player who never had it, and a Riptide indicator not lighting for the
player who did. Only while the raid is forming; a reload clears it.

Two places wrote the new unit BEFORE calling SetUnit and ignored the
result. SetSlotOwnerUnit guards on `owner.unit == unit` at the top, so an
optimistic write turns any refusal into a PERMANENT desync: the owner
reads as retargeted, every later call short-circuits, and the container
stays bound to the previous occupant until a reload. The regen drain had
it worse -- it clears pendingUnit and drops the owner from the registry
first, so a refusal lost the retarget outright.

Both now commit only on success. On failure the old token is left in
place, which is exactly what the combat branch already documented
("owner.unit is left on the OLD token deliberately, so GetUnit stays
truthful ... and a repeat call simply re-queues"); the OOC path was the
one place not honouring its own contract. The drain re-queues after the
loop, never inside it -- adding a key during a pairs() traversal is not
legal, only nil-ing an existing one is.

Also reads the engine back. AuraContainerSharedMixin:GetUnit returns a
plain string, not a secret, so "did the retarget land" is directly
answerable and was simply never asked -- on the slot path and in
confirmRetarget, which until now only checked that A parse happened and
not which unit it parsed. A mismatch is reported, not repaired: the unit
is already committed and Blizzard's SetUnit no-ops when its own token
matches, so the cure would be a rebuild.

⚠ Candidate fix plus a detector, NOT a confirmed diagnosis. SetUnit is
plain mixin state and rarely refuses, so these may be latent rather than
the reported cause. The read-back is the part that settles it: if this
recurs, the log names the wrong unit instead of leaving it looking like a
filter fault.

(cherry picked from commit 5a780c35d71e17631587bb41842810a981f92505)
…obals

GetItemSpell and GetItemCount live in Blizzard_DeprecatedItemScript, which
12.1.5 removes outright. Both were exact 1:1 forwards to C_Item, and both
were already dead for anyone running without loadDeprecationFallbacks, so
the item pickers in CC:GetSlotItemInfo and CC:GetItemInfoById could error
on a nil global today.

CC:GetItemCount fell back to the alias of the very function it had just
called, so the fallback is dropped rather than renamed.

(cherry picked from commit 2d40a8a215a6431582d35192788e6f45218d21c8)
…payload names

Reported on live 5.3.1: the RES text intermittently does not appear in M+ or
raid, while the corpse still shows Blizzard's own res glow and the target can
accept. One reporter saw it for every battle rez they cast.

What is proven from the code:

  * INCOMING_RESURRECT_CHANGED is the ONLY show driver for this icon. The
    "pending accept" (yellow) state is derived from having previously observed
    the cast -- resCache[unit] == 1 -- so a frame that never saw the casting
    edge can reach neither state and falls through to Hide().
  * ResTimerCleanup only ever hides. It never discovers.
  * The only recovery is UpdateAllStatusIcons, reachable from a full-frame
    refresh or a combat transition. Inside an M+ pull or a boss fight neither
    happens, so a single missed update lasts the whole fight -- which is the
    envelope every report describes.

So this icon is the one where dropping one update is permanent, and it was the
only status icon routing that update through a single unitFrameMap[arg1]
lookup. The payload is typed UnitTokenVariant (retail dump,
UnitDocumentation.lua:3497): the token delivered is not guaranteed to be the
token the map is keyed by.

Blizzard's own CompactUnitFrame registers this event with a plain RegisterEvent
and calls CompactUnitFrame_UpdateCenterStatusIcon(self) without reading the
payload at all -- every frame refreshes itself. Mirror that: walk all frames,
plus a separate pinned walk since IterateAllFrames has no pinned arm. The event
fires when a resurrection starts or stops on a group member, not on a timer, so
the sweep is affordable.

⚠ This removes the class of failure, not a confirmed trigger. I have not
reproduced the miss in game and this does not claim to name it. Two other
threads stay open: whether an instant battle rez presents an observable casting
edge at all, and that GetStatusIconFadeAlpha multiplies this icon by
fadeDeadIcons -- an icon which by definition only ever exists on a dead unit.
Field report, Krathe 2026-09-07: joined a raid from player housing; every
Aura Designer icon vanished -- including on his OWN frame -- and did not come
back until a reload. The park was clean (not one "believed dark but not
locked" warning in 5,043 entries). It was this latch. Three faults, three
fixes.

1. THE SELF-EXEMPTION WAS A STATE TEST, AND IT RACED

   Frames/Update.lua gated on UnitIsUnit(unit, "player"). One second after a
   reload, with the roster still building, that answers FALSE for your own
   raidN token while UnitExists is already true and UnitIsVisible already
   false -- so the branch ran on the player and latched him. The trail:

       19:19:57  --- UI Reload ---
       19:19:58  visibility latch ON unit=raid9      <- his own token

   Now it requires the identity to have RESOLVED: two GUIDs that both read
   back as plain strings. Anything else -- nil during roster build, a secret
   under identity restriction, a pcall failure -- leaves the unit shown,
   which is this latch's standing fail-safe rule. UnitGUID is localised like
   its neighbours; the edge is on a per-tick path.

2. THE VERDICT WAS STORED IN THE CONTAINER, AND CONTAINERS ARE RETARGETED

   This is the one that made it permanent. The registry is keyed by UNIT;
   the actuation was keyed by whichever container pointed at that unit AT
   THAT INSTANT. SetUnitVisibilityLatched(unit, nil) therefore could not
   reach a container that had since moved -- and Handle:SetUnit re-seeded it
   from its NEW unit, which during a raid join is very likely also latched.
   The verdict migrated with the container instead of staying with the unit.

       19:20:12  debuff:    retarget raid8 -> raid9
       19:20:16  defensive: retarget raid9 -> raid8
       19:20:18  defensive: retarget raid8 -> raid9
       19:20:32  raid2->raid1, raid3->raid2, raid4->raid3, raid5->raid4 ...

   Nothing could recover it: ReconcileLatches walks the registry and calls
   the same unit-scoped function, and checkDarkMismatch only ever warned in
   the LEAK direction. A reload worked because it discards every handle.

   Nothing stores the verdict now. Every actuation asks the registry for the
   unit it is bound to RIGHT NOW (unitVisLatched / handleVisDark /
   slotVisDark); _visLatched survives only as a memo of the last application,
   to gate redundant work. Both _setVisLatch setters ignore their argument
   and recompute, so every existing caller became correct without a call-site
   change and none can poison a handle by reasoning about the wrong unit.

   ReconcileLatches now re-asks every handle and slot -- idempotent, since a
   container that agrees returns on the memo check -- and WARNS when it finds
   one held dark for a unit that is not latched. That direction had no
   detector at all, which is why the log showed nothing.

   This is the converse of the August death-latch fix: that established that
   an actuation keyed by UNIT needs an edge keyed by UNIT. The half never
   checked was that an edge keyed by UNIT needs an ACTUATION keyed by UNIT.

3. IT DARKENED POOLS THE LEAK CANNOT REACH

   The guard exists for the PLAYER filter token failing open, which can only
   affect pools whose filter names PLAYER. Krathe's session: 2 of 10
   container filters were source-relative; all 10 were darkened. The two
   halves both come out of his log -- the PLAYER-token partition broke 5
   times and every one carried vis=0, while the same probe ran 32 times at
   vis=1 without a break; and 17 raid units latched in a single tick while
   their containers still reported live helpful counts (raid18 held 8
   throughout). So the trigger is real and the scope was not.

   handleVisDark/slotVisDark gate on _idGateSourceRelative -- a flag this
   file already computed in five places and read in none outside the debug
   dump.

   ☠ This overrules a documented 2026-08-18 decision, at Krathe's explicit
   direction. That note said every pool on a unit outside your world is
   stale, not just source-relative ones, and narrowing once left a
   cross-instance unit showing a stale debuff row. It is not retracted --
   the comment above SetUnitVisibilityLatched now carries both sides and
   names the switch to reverse it. What changed is the price: UnitIsVisible
   goes false for out-of-RENDER-range group members, not only cross-instance
   ones, so the blanket response fires constantly in a raid.

The death latch is untouched and keeps its per-unit blanket scope: death
really does freeze every pool, with no aura event to follow.

⚠ Not verified in game. Reproduce by joining a raid from an instance.
@Krathe82
Krathe82 force-pushed the krathe/live-5.3.1-fixes branch from f5aafdb to f7a20c6 Compare September 8, 2026 02:27
@Krathe82 Krathe82 changed the title Seven live 5.3.1 fixes: profile switches, the dispel ring, a fatal GetChildren, Max Debuffs, retargets, the removed item globals, and the RES icon Eight live fixes: profile switches, the dispel ring, a fatal GetChildren, Max Debuffs, retargets, the removed item globals, the RES icon, and a stranded visibility latch Sep 8, 2026
DanderBot pushed a commit that referenced this pull request Sep 9, 2026
…r GUID is read once, and the RES walk uses the handler's own pinned iterator

Follow-ups from the PR #261 review. handleVisDark now returns false for a
parentDrivenVisibility handle, matching every other latch path; the reconcile
warning names the retune case as well as the retarget one; Update.lua caches
the player's own GUID after one guarded read instead of two pcalls per unit per
update, and its comment records the alternative reading of the 19:19:58 trail;
Headers.lua's INCOMING_RESURRECT_CHANGED branch walks pinned frames through the
same local upvalue its neighbouring branches use.

(cherry picked from commit 579da52)
DanderBot pushed a commit that referenced this pull request Sep 11, 2026
Four live 5.3.1 fixes: aborted profile switches, the dispel ring, a fatal GetChildren, and Max Debuffs
@DanderBot
DanderBot merged commit e5f74cd into DanderBot:main Sep 11, 2026
DanderBot pushed a commit that referenced this pull request Sep 11, 2026
…r GUID is read once, and the RES walk uses the handler's own pinned iterator

Follow-ups from the PR #261 review. handleVisDark now returns false for a
parentDrivenVisibility handle, matching every other latch path; the reconcile
warning names the retune case as well as the retarget one; Update.lua caches
the player's own GUID after one guarded read instead of two pcalls per unit per
update, and its comment records the alternative reading of the 19:19:58 trail;
Headers.lua's INCOMING_RESURRECT_CHANGED branch walks pinned frames through the
same local upvalue its neighbouring branches use.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants