# Nem: Healer Alerts — Full Code Review

**Date:** 2026-06-05
**Version reviewed:** 12.0.25 (branch `main`)
**Scope:** Core engine + 7 spec modules + locales/packaging (~14,700 lines Lua)
**Method:** One reviewer per major file, shared rubric (correctness, WoW API/taint safety, performance, structure/duplication, framework conventions, saved variables). Three highest-impact findings independently re-verified against source.

---

## Overall assessment

The addon is **in strong shape and largely ship-quality for the active specs**. The engineering discipline is unusually high for a WoW addon:

- **Taint safety is genuinely thorough.** Every `C_Spell` / `C_UnitAuras` / `C_Traits` read is `pcall`-wrapped and `issecretvalue`-guarded before use. The known secret-value / GCD-residue traps from David's API ledger are handled deliberately, not accidentally.
- **Performance is well-built for combat.** The core OnUpdate self-disarms when idle, group-unit lists are cached and dirty-flagged, CUF aura handling filters on per-unit deltas before touching frames, and spec modules use event-driven presence caches with deferred/batched CUF glow drains instead of per-frame rescans.
- **Saved-variable migration is textbook** — monotonic `db.ver` chain, runs before `MergeDefaults`, only nils removed/renamed keys.
- **Framework conformance is high** across the shipped specs.

There are **no confirmed crash-class bugs in the four shipped/active specs.** The real issues cluster into: (1) a small number of latent correctness traps, (2) the three *deferred* specs (Shaman/Paladin/Evoker) which are feature-complete but carry real bugs and, for Evoker, do not yet meet the mandatory perf contract, and (3) pervasive cross-spec duplication that is the root cause of several findings.

### Severity legend

| Severity | Meaning |
|----------|---------|
| **Critical** | Crashes, taint lockout, or data loss in normal play. **(none found)** |
| **High** | Feature silently broken, or a latent trap already shown to bite once. |
| **Medium** | Wrong behavior in an edge case, or a real perf/maintainability cost. |
| **Low** | Cosmetic, dead code, consistency, or convention drift. |

---

## Priority findings (the short list)

| # | Sev | File:line | Issue | Verified |
|---|-----|-----------|-------|----------|
| 1 | High | `Specs/ShamanRestoration.lua:1004-1013` | Surging Totem (`st`) alert is `hasTimer=true` but never sets `stActive/stExpire/stTimeMod` — voice cue fires, on-screen text + countdown never render | ✅ confirmed |
| 2 | High | `Specs/DruidRestoration.lua:58` | `ABUNDANCE_NODE_ID = 103876` breaks the `82xxx` node-ID family and is untagged; if it's an entry/def ID not a node ID, `GetNodeInfo` returns nil and the Abundance alert is permanently disabled | ✅ confirmed value; needs in-game check |
| 3 | High | `Specs/PriestDiscipline.lua:1316-1320` | Atonement presence cache keys by unit token; rebuild (`player`) and incremental update (`raidN`) disagree in raids → `atonCachedCount` drift → false/missed "Spread Atonement" criticals | Logic-traced, needs in-game check |
| 4 | High | `NemHealerAlerts.lua:466-487` | `EvalSpellReady` uses `GetSpellCooldown`, which returns `0/0` for charge-based spells even while on CD (logged empirical failure). Any spec pointing a charge spell at this helper sticks the alert on forever | ✅ matches ledger |
| 5 | High | `Specs/EvokerPreservation.lua` (whole file) | Missing mandatory perf instrumentation; synchronous unthrottled CUF glow; taint-unsafe `CountActiveReversions`. **Not ship-ready even after un-commenting registration** | ✅ confirmed |
| 6 | Med | `Specs/PaladinHoly.lua:584` | `hs` ("Holy Shock Charges Capped") evaluated with `EvalSpellReady` (finding #4's footgun) instead of `EvalChargeCap` on a charge-based spell | ✅ confirmed |
| 7 | Med | `Locales/zhTW.lua` | Registered zhTW locale translates **0 of 120** UI text keys (voice cues only) → UI is 100% English for zhTW clients while advertising TW support | ✅ confirmed |

**Recommended fix order:** #1 and #2 are silent feature breakage in shipped/active content and cheap to fix. #4 is a shared footgun worth fencing (header warning + guard) before the next charge-based spell lands. #3 needs an in-game repro before the keying change. #5/#6/#7 are gated behind the deferred specs / locale decision and can follow.

---

## Cross-cutting themes

These explain several individual findings and are where the highest-leverage refactors live.

### A. The `EvalSpellReady` charge-spell footgun (root of #4 and #6)
`GetSpellCooldown` returns `start=0, duration=0` for charge-based spells even on cooldown (logged 2026-05-27, `/nha mbtrace`). Disc Priest already migrated Mind Blast off this path, but the **shared helper remains a trap**: Paladin's `hs` (#6) currently uses it on Holy Shock. Fix the helper's contract, not just each caller — add a `GetSpellCharges` cross-check when charges exist, or at minimum a header warning that charge spells must use `EvalChargeCap`.

### B. Massive cross-spec duplication
Three independent reviewers flagged the same shapes copy-pasted across spec files:
- **Talent-check boilerplate** (`GetActiveConfigID → GetNodeInfo → activeRank/entry → GetDefinitionInfo`): ~90 lines in Druid, ~200 lines in Holy Priest, repeated in every spec. Candidate: `NHA.CheckTalentNode(nodeID, entryID, spellID)` + `NHA.CheckHeroTalentNode(...)` on the core.
- **Taint-safe aura helper block** (`_toNumber`/`SafeNum`/`IsPlayerOrUnknownSource`/`HasValidInstanceID`/`FindAuraOnUnit`): ~80 lines duplicated verbatim in Shaman/Paladin/Evoker. Candidate: a shared `NHA.AuraScan` module alongside the existing `NHA.AlertHelpers`.
- **Perf-instrumentation block**: ~200 lines duplicated.

This duplication is the direct cause of Evoker's bugs (#5) — its copies of the helpers lag the other specs', so it never got the taint guards and deferred-drain pattern the others have. Centralizing would have prevented them.

### C. Stale spec-module contract documentation
Multiple reviewers independently found that the wiki spec-contract claims "Return values from `OnEvent` are ignored," but the core dispatcher actually does `local handled = mod:OnEvent(...); if not handled then ScheduleEvaluate() end` (`NemHealerAlerts.lua:2964-2966`). Every shipped spec correctly relies on the **real** behavior (return `true` to suppress the redundant auto-eval). **The code is right; the doc is wrong.** A future spec author following the doc would get double-evals or silently killed evals. Fix the contract source, not the code.

### D. `GetClassColor` bare-global drift
Druid, Disc, Monk, Shaman, and Paladin all call the legacy bare global `GetClassColor` in their options-build path, while the core's own helper (`NemHealerAlerts.lua:137`) deliberately routes through `C_ClassColor.GetClassColor` with a fallback. Cold path, so perf-irrelevant, but it's a consistency/longevity nit worth a suite-wide sweep to the core helper.

---

## Per-file findings

### NemHealerAlerts.lua (core engine) — healthy

**Summary:** The engine is the strongest file. Secret-value handling is disciplined, OnUpdate self-disarms, the CUF aura-delta filter avoids per-frame rescans, and SV migration is clean. Defects are latent edge cases, not live crashes.

- **[High]** `466-487` `EvalSpellReady` — charge-spell footgun (see theme A / finding #4).
- **[Medium]** `1221-1246` `ToggleTest` — the 10Hz `testTicker` is only cancelled in `ToggleTest`'s off-branch. On `PLAYER_SPECIALIZATION_CHANGED`, `ActivateModule`→`DeactivateCurrentModule` nulls `activeModule` but never cancels the ticker; it keeps firing against a torn-down module (it early-returns harmlessly, but it's a leaked timer). Cancel/refresh the ticker in `ActivateModule`/`DeactivateCurrentModule`.
- **[Medium]** `889-961` & `972-1018` — the timer-threshold color block (`{2.0,0.667,1.0,0.0}`...) is duplicated verbatim between `OnUpdateBody` and the test-mode branch of `Evaluate`. Extract a `DEFAULT_TIMER_THRESHOLDS` constant + `ApplyTimerColor(fs, remaining, thresholds)` helper.
- **[Medium]** `225, 233` `GetSoundPath` — fallback sound is `BUNDLED_SOUNDS["Bell"]`; the framework's canonical resolver specifies `RobotBlip`. Works (both exist) but drifts from the locked pattern. Change to `RobotBlip` or document the exception.
- **[Low]** `920` `OnUpdateBody` — `(expire - GetTime()) / timeMod` has no zero-guard; a spec setting `timeMod = 0` produces `inf`/`nan` into `SetText`. Cheap to guard.
- **[Low]** `701-724` `GetSpecID` — the fallback loop (710-721) re-calls `GetSpecialization()` (same source the primary already used), so it can't recover a case the primary missed. Effectively unreachable; remove.
- **[Low]** `2021-2030` `MakeSlider` `OnTextChanged` — `setter(val)` + `ApplyDisplaySettings()` fire on every keystroke with no clamp (clamp only on focus-lost), relayout on partial input. Clamp in `OnTextChanged` too.
- **[Low]** `62-65` `SafeCall` — swallows caught errors with no debug path; a silent spec bug is invisible. Consider a debug-mode that surfaces the caught error with `label`.
- **[Low]** `1142-1145` `InitDatabase` — `NemHotAlertsSV → NemHealerAlertsSV` rename only runs when the new table is nil; if both exist the old is silently dropped. Almost certainly fine.

**Clean:** WoW API safety (no protected/lockdown violations; `hooksecurefunc("CompactUnitFrame_UpdateAll")`, `EnumerateFrames`, `IsForbidden()` gating all correct), performance hot path (no allocations), saved variables (migration + key derivation textbook). Locked framework constants (PW=668, height 580, scroll/scrollbar geometry, cyan `#00CCFF`, version footer, title geometry) all match.

---

### Specs/DruidRestoration.lua — healthy, one high-value verify

**Summary:** 2557-line mature module. Sound core mechanics, extensive taint safety, documented WG/Swiftmend DurationObject-unwrap and GCD-residue workarounds, generation-counter timers, batched CUF glow drain. Conforms to the spec contract.

- **[High]** `58` `ABUNDANCE_NODE_ID = 103876` — see finding #2. Breaks the `82xxx` node family; untagged while siblings are `live-verified 2026-05-27`. If it's an entry/def ID, `CheckAbundanceTalent` (310) always returns false and the Abundance alert is dead. **Verify in-game whether `abundanceActive` has ever fired.**
- **[Medium]** `1713, 1979` — two handlers call immediate `NHA.Evaluate()` instead of debounced `NHA.ScheduleEvaluate()`. Both already sit behind their own `C_Timer.After`, so it's defensible, but it deviates from the contract's stated re-eval path and every other site in the file.
- **[Medium]** `170, 189, 1482-1493, 1505-1508` — `castlb` and `lb` share `yOffset` (-75) and both are `VOICE_PRIO_CRITICAL`, relying entirely on a mutual-exclusion invariant that has a narrow race window (across the 0.05s `lbScanPending` gap). Add an explicit guard or comment.
- **[Low]** `95-148` — five `state` fields (`swLogEnabled`, `swLogLastCastAt`, `swLogLastPredicted`, `refoInstID`, `state._perf`) are used but never declared in the canonical `state` table; `refoInstID` in particular is real combat state that `ClearAllState()` doesn't reset (stale ID survives spec re-enable). Declare them and reset `refoInstID`.
- **[Low]** `25-74` — 14 declared constants are never referenced at runtime (verified-ID documentation). Either move to a labeled "reference IDs (not used at runtime)" block or drop. Note `WILDSTALKER_SUBTREE_ID` is defined but no Wildstalker logic exists.
- **[Low]** `1881` — `state.sotfEmpoweredWindowExpire = now + 18.0` uses a bare `18.0` while the adjacent buff duration is named (`SOTF_BUFF_DURATION = 15.0`). Promote to `SOTF_EMPOWERED_WINDOW_SEC`.
- **[Low]** `293-382` — five talent-check functions repeat boilerplate (theme B).
- **[Low]** `1999` — bare-global `GetClassColor` (theme D).

**Clean:** WoW API safety (strong — DurationObject unwrap, GCD-residue rejection, charge-vs-cooldown distinction all correct), performance (event/timer-driven, no OnUpdate, GUID-deduped iteration, deferred CUF drain capped at 4 frames/tick), framework conventions.

---

### Specs/PriestHoly.lua — healthy

**Summary:** 2556-line module — rolling-charge models for PoM/Serenity/Sanctify, manual CDR system, 8 talent gates, deferred CUF drain, full perf instrumentation. Unusually disciplined; no critical correctness or API-safety bugs.

- **[Medium]** `240-515` — eight near-identical talent-check functions, ~200 lines of duplication (theme B). Highest-value dedup target in the file.
- **[Low]** `1611-1612` — stale comment; the PoM charge-suppression it describes is enforced in the `SPELL_UPDATE_CHARGES` handler at 2077, not in `Evaluate`. Reword.
- **[Low]** `1320` — `state = state` module field is a dead/unused surface (nothing reads `mod.state`). Confirm against the contract before removing.
- **[Low]** `1356, 1368, 1375` `ClearAllState` resets charges to **full** — if ever called mid-encounter it marks all three spells ready until the next cast corrects it. Verify callers are deactivate/login only; if it can fire in combat, reset to 0 + armed recharge.
- **[Low]** `1475, 1501` — CUF glow path computes `(sa.expirationTime - now)/sa.timeMod` then compares `> 0`; `SafeNum` on a secret value yields a secret *number*, not a throw, so the `>` would taint-throw in M+. Currently safe **only because** `RENEW_ID`/`POM_ID` are whitelisted buffs. Latent trap if a non-whitelisted spell is added to this path. Add a defensive `issecretvalue` early-out.
- **[Low]** `38-99` — several CDR-seconds constants are tooltip-derived, not empirically confirmed per the ledger discipline. Calibration dials, not defects.

**Clean:** API safety (all calls verified unrestricted; every read `issecretvalue`-guarded), event registration, performance (no OnUpdate, bounded tickers, event-driven group iteration, batched CUF), timer correctness (gen-counter invalidation), framework conventions.

---

### Specs/PriestDiscipline.lua — healthy, one high-value verify

**Summary:** 2119-line mature module. Heavy taint discipline, gen-counter timers, incremental Atonement presence cache, deferred CUF drain. Conforms to contract. Risks concentrate in the Atonement count path and charge-tracker timing.

- **[High]** `1316-1320` (+ `171-187`) — see finding #3. `RebuildAtonPresenceCache` keys `atonPresence` by the first unit token (player, index 1), but the incremental `UNIT_AURA` path skips the `player` token in raids expecting `raidN` to carry it. The keys don't reconcile → player double-counted or stale entry never clears → `atonCachedCount` (the entire basis for the "Spread Atonement" CRITICAL) drifts. **Fix: key by GUID in both paths.** Needs an in-game raid repro.
- **[High]** `1235-1239` — Rift rising-edge latch writes `riftActive` and `riftWasActive` to the same value on the same line, with no separation from the play-check, unlike the aton/vs/pws structure (1245-1247). The `hasTimer` countdown can render one frame stale; the asymmetry with the other three alerts is a latent trap. Mirror the trailing-latch structure. *(Note: lower real-world impact than the severity suggests — the reviewer hedged this; treat as "restructure for safety," not a live break.)*
- **[Medium]** `1438, 1442` & `1357-1364` — suppression window can be armed twice and overshoot the true recharge on a single cast (predicted `cdDur` vs live-API disagree). `chargeTimerSet` is now dead bookkeeping (invalidation is via `chargeGen`) that `TryInitDiscChargesFromAPI` still reads and can wrongly block re-arming. Drop `chargeTimerSet`; clamp `suppressUntil` to never exceed the live-API recharge end.
- **[Medium]** `1443` — `C_Timer.After(cdDur+0.01, ScheduleEvaluate)` allocates a fresh closure on every Penance/Radiance/MB cast and is redundant (`_OnDiscChargeRecover` already re-evaluates). Delete the line.
- **[Medium]** `1322-1331` — player `UNIT_AURA` always schedules a 0.1s full `NHA.Evaluate()` even when nothing relevant changed (every HoT tick/proc). Gate the reschedule on whether `updateInfo` touched a spell this module cares about.
- **[Low]** `1200` — `pairs(discChargeTrackers)` hash-walks the 3-entry table every Evaluate; canonical pattern is a pre-built array with `ipairs`. Negligible at 3 entries.
- **[Low]** `694, 1218, 2018-2019` — dead `state.mbState` vestige from the pre-charge-tracker implementation (only the debug dump reads it). Remove.
- **[Low]** `1325, 1327, 1501` — raw `NHA.Evaluate()` instead of throttled `ScheduleEvaluate()` (already behind a debounce, so low impact).
- **[Low]** `1618` — bare-global `GetClassColor`/`UnitClass` (theme D).

**Clean:** WoW API safety (every read pcall+issecretvalue-guarded; DurationObject unwrap handles all shapes; charge-based MB correctly off `GetSpellCooldown`; GCD-residue filter `DISC_API_MIN_TRUSTED_DUR=3.0`), spell IDs (all match comments + ledger), framework conventions, threshold defaults.

---

### Specs/MonkMistweaver.lua — healthy

**Summary:** 1573-line module — RM spread count, EM-on-Soothing-target, TFT ready, CUF glows, self-contained perf harness. Strong taint discipline. The documented TFT 30s→24s collapse is handled correctly and deliberately (constants + gen-counter + `/nha tftlog` instrument — exactly the "build the instrumentation that proves it" pattern).

- **[Medium]** `1032, 1057, 1397, 1400` — the Soothing-Mist grace window is `SOOTH_GRACE = 3.0` (used at 862) but four other sites hardcode the literal `3.0`. If retuned, the `Evaluate` gate and the deferred re-eval timers silently disagree → ENV alert flickers at the boundary. Replace all four literals with `SOOTH_GRACE`.
- **[Medium]** `346-356, 1083, 1097` — TFT cooldown modeled as a flat constant (24/30s) gated on the HoJS *talent*, with a frank `-- ASSUMPTION` that the buff procs every cast. Defensible (avoids the GCD-residue API trap) but correctness depends on an external balance invariant with no runtime check. Optional future fix: gate on the actual HoJS buff aura, not the talent flag.
- **[Low]** `589` `NeedsTicker` always returns false and the core never calls it. Dead code.
- **[Low]** `838` `_safetyNetLastRun` declared, never used. Remove.
- **[Low]** `333, 396` `state.tftLastRecoverAt` set + read (debug only) but not reset in `ClearAllState`, unlike every other `tft*` field.
- **[Low]** `855, 884` — `local now = GetTime()` declared twice in `Evaluate` (second shadows first). Drop the redeclare.
- **[Low]** `924-925` — bare-global `GetClassColor` + magic fallback color triple (theme D).
- **[Low]** `968-1208` — relies on the real `OnEvent` return-value behavior (theme C); code correct, doc stale.

**Clean:** API safety (all five APIs verified unflagged; hero-talent detection correctly on `GetActiveHeroTalentSpec`), event registration, performance (no OnUpdate/CLEU, incremental RM cache, batched CUF drain), spell IDs, the TFT quirk handling.

---

### Specs/ShamanRestoration.lua — deferred (registration commented out), one shipping-blocker bug

**Summary:** 1557-line feature-complete module, 6 alerts. Registration commented out (`v12.0.25 — spec not shipped`). Taint-safe, event-driven caches, deferred CUF drain, full perf instrumentation present.

- **[High]** `1004-1013` (+ alert def `588-598`) — see finding #1. `st` ("Surging Totem Expiring") is `hasTimer=true`, but `Evaluate` only calls `PlayAlertSound("st")` and never sets `state.stActive/stExpire/stTimeMod`, which the core renderer (`NemHealerAlerts.lua:900/918`) reads to draw the text row + countdown. **Result: voice-only alert; the `* RECAST SURGING TOTEM *` text and timer never appear.** Set `stActive`, `stExpire = stStartTime + stDuration`, `stTimeMod = 1`.
- **[Medium]** `39 / 34` — `SURGING_TOTEM_SPELL_ID = 444995` duplicates `TOTEMIC_HERO_SPELL_ID = 444995`; the comment even says "verify in-game if alert never fires." If the totem-object spell ID differs from the talent anchor, `GetTotemInfo` name-match never succeeds and the whole ST feature no-ops. Verify the two are genuinely the same ID.
- **[Medium]** `1004-1013` — the `elseif remaining <= 0` ST-warn reset is redundant with `_refreshSurgingTotemCache` clearing `stWarnFired` on `PLAYER_TOTEM_UPDATE`; masks intent. Clarify.
- **[Low]** `1084-1086` — redundant `unit:sub(1,5)=="party" and unit:find("^party%d")` runs a pattern on the hot `UNIT_AURA` path. Use a `match`/set lookup.
- **[Low]** `1273` — bare-global `GetClassColor`/`UnitClass` (theme D).
- **[Low]** `52-58` — `GetSpellInfo` fallback is dead on modern retail (deprecated/removed; primary path is `C_Spell.GetSpellName`). Delete.
- **[Low]** `316` `GetHSTCharges()` consumed only by debug slash. Fine as a debug helper.

**Clean:** taint safety (exemplary), CUF glow deferral, event registration, combat-gate latch discipline, perf instrumentation.

---

### Specs/PaladinHoly.lua — deferred, one charge-vs-cooldown verify

**Summary:** 948-line feature-complete module, 5 alerts. Registration commented out (deferred, v12.0.25). Cleaner than Shaman.

- **[Medium]** `584` (alert def `239, 247`) — see finding #6. `hs` ("Holy Shock Charges Capped") uses `EvalSpellReady` on charge-based Holy Shock (theme A). If "charges capped" is the intent, use `EvalChargeCap(state.hsReadyState, HOLY_SHOCK_ID, "hs")`. Verify in-game (depends on Holy Shock's talented charge count).
- **[Low]** `158-159` `PollVirtueCooldown` — does not `issecretvalue`-check `info.startTime`/`info.duration` before storing, unlike Shaman's UL path; in M+ a secret duration could be stored. Comparison is local/discarded so impact is low, but inconsistent with the file's own taint discipline.
- **[Low]** `307-312` vs `421-447` — `BEACON_OF_VIRTUE_ID` deliberately absent from `cufRelevantSpells` (Virtue rides the BoL aura). Correct; add a one-line comment so a future reader doesn't "fix" it.
- **[Low]** `623-626` — bare-global `UnitInParty`/`UnitInRaid` on the hot `UNIT_AURA` path (theme D).
- **[Low]** `547-548` — empty `RefreshGlows` stub still timed by the perf harness (`REFRESH` block reads ~0). Harmless.

**Clean:** group iteration (GUID-deduped, early-return), CUF deferral + 4-frame budget, talent detection (pcall-guarded, refreshed on the right events), Holy Power cap (`EvalPowerCap` with `Enum.PowerType.HolyPower` fallback), perf instrumentation.

---

### Specs/EvokerPreservation.lua — deferred, NOT ship-ready

**Summary:** 411-line module, 4 alerts — the thinnest and visibly least finished. Registration commented out. Multiple shipping blockers.

- **[High]** whole file — **no perf instrumentation** (no block tags, no instrumented CUF worker, no path tags, no `perf` slash commands). The framework's perf contract is mandatory before a new spec ships. Port the perf block from Paladin/Shaman.
- **[High]** `329-331 / 260-324` — `EvaluateCUFGlow` runs `DoEvaluateCUFGlow` **synchronously** for every CUF frame on the core hook, with no dirty-set / `C_Timer.After(0)` drain and no 4-frame budget. On a full raid this is two `FindAuraOnUnit` scans per frame per hook call — the exact unthrottled pattern the perf contract warns against. Adopt the deferred drain from the other specs.
- **[Medium]** `198-212 / 348-354` — `CountActiveReversions` does up to 2×groupSize aura reads on **every** Evaluate with no presence cache and no GUID dedup (~40 API calls per tick in a 20-raid). Build an event-driven presence cache like Shaman's Riptide path.
- **[Medium]** `204-205` — `aura.auraInstanceID ~= 0` and `aura.sourceUnit == "player"` bypass the taint-safe helpers (`HasValidInstanceID`/`IsPlayerOrUnknownSource`) defined in the same file. In M+ those secret reads can throw — the only taint-unsafe aura access in the file, sitting in the hottest scan. Route through the helpers.
- **[Low]** `371-372` — empty `OnActivate` stub never seeds caches/talent flags (contrast Shaman/Paladin which prime on activate).
- **[Low]** `21-31` — `ECHO_DREAM_BREATH_ID`, `LIFEBIND_ID` are dead constants.
- **[Low]** `16` — `issecretvalue` imported but never used (symptom of the missing guards above).

**Clean:** the `FindAuraOnUnit` scanner and taint-safe helper set are correct (just under-used), alert definitions/defaults/colors/priorities well-formed, Dream Breath path correct, `ClearAllState`/`ClearAllGlows` correct.

---

### TOC / Packaging / Localization — healthy

**Summary:** Packaging surface is in good shape. TOC correct (all 15 referenced files exist; load order libs→locales→core→specs), SavedVariables global matches the Lua, dependency handling fully defensive, `.gitattributes`/`.gitignore` correctly strip dev cruft from the CurseForge zip. The one substantive issue is the zhTW stub.

- **[Medium]** `Locales/zhTW.lua:14-21` — see finding #7. 0 of 120 UI text keys translated (only 28 sound-file overrides). Honest stub (header says so), but registering it advertises TW text support that doesn't exist. Either translate, or document as a voice-only pack.
- **[Low]** `AGENTS.md` — points at `C:\Users\David\Documents\Claude\Context_Files\...`, the **deleted OLD vault** (gone since the 2026-05-23 NemWiki migration). `export-ignore`d from the zip so harmless to users, but misleads any agent that reads it. Repoint to NemWiki or delete.
- **[Low]** `NemHealerAlerts.lua:2139` — `title:SetText("Nem: Healer Alerts")` is the only hardcoded UI literal (brand title; arguably should never be translated). Leave.
- **[Low]** `Locales/Locale.lua` — `displayNames` lists 11 locales but only enUS/zhTW are registered; cosmetic only (the dropdown iterates `registry`, not `displayNames`).

| Locale | Keys present | Missing vs enUS | Status |
|--------|--------------|-----------------|--------|
| enUS | 120 | 0 | Canonical / complete |
| zhTW | 0 text; 28 sound overrides | 120 | Stub — UI 100% English, voice cues localized |

**Clean:** TOC correctness, SavedVariables (+ clean `NemHotAlertsSV` legacy migration), dependency safety (all four libs optional + nil-guarded, degrade gracefully), `.gitattributes`/`.gitignore`, no secret/path leaks, Media (55 `.ogg` + 28 zhTW `.mp3`) and Fonts (47 `.ttf`) bundles legitimate.

**Operational note (outside rubric):** a full `.git` directory lives at the addon root — the live retail AddOns folder *is* the git working tree. Harmless for the zip (clean export), but a stray `git clean -fdx` there would nuke `.curseforge/` and `.claude/`.

---

## What's notably good (don't regress these)

- Secret-value / taint handling across the whole codebase is the strongest part of the addon. The `pcall` + `issecretvalue` + `SafeNum` discipline is consistent and matches the empirical API ledger.
- Core performance architecture: OnUpdate self-disarm, cached/dirty-flagged group lists, CUF aura-delta filtering, deferred + budgeted CUF glow drains.
- Saved-variable migration discipline (monotonic `db.ver`, runs before `MergeDefaults`, only nils removed keys).
- The Monk TFT handling is a model example of the "instrument it rather than argue about it" principle.

---

*Generated by parallel multi-agent review. Findings #1, #2, #6 re-verified directly against source; #4 cross-checked against the API ledger. The remaining High items (#3 Atonement drift, Disc rift latch) are logic-traced and flagged for in-game confirmation before changing the keying/latch structure.*
