Files
benilla-octo/crates
gromandClaude Opus 5 780ca25833 npc: the interaction token reaches the VM before the window's own event
HCQuest raised `bad argument #1 to 'strupper' (string expected, got nil)`
at `HCQuest.lua:16` once in the player's 2026-10-16 session, from
`questDetail` on `QUEST_DETAIL`. Its three arguments are `GetTitleText()`,
`QuestFrameNpcNameText:GetText()` and `GetObjectiveText()`, and the `and`
short-circuit means the giver is only read for a quest whose title matches
one of the addon's 49 — which is why it fired once and not on every quest.
So the nil is the name string, and `QuestFrame_SetPortrait` fills it from
`UnitName("npc")` (`QuestFrame.lua:63`).

`feed_interact_npc` seats `InteractNpc` before every feed, but the `"npc"`
token only reaches the VM in `feed_units`, and `feed_units` and `feed_quest`
are two systems in one `UiFeed` with no edge between them: the order was
declared by nothing, so `QUEST_DETAIL` could be signalled into a VM whose
`"npc"` was still absent. `SetText(nil)` then leaves the string empty for
the life of the panel, and the stock quest frame shows no giver name either.

Five window feeds were in that position; each now declares
`.after(crate::ui_unit::UnitFeed)`, as `feed_auction` and `feed_trainer`
already did, with the stock line that reads the token in the comment:
quest, gossip (where the chain's own `Turtle_ArenaUI.lua:285` and
`Turtle_GuildBankUI.lua:378` gate on `UnitName`/`UnitExists("npc")`, so a
late token means the window simply never opens), bank, taxi, tabard.

The reference needs no such edge: `CGGameUI::SetInteractNPC` writes
`[0xb4e2d0]` on the interact itself, so the pointer is live before any
window's `SignalEvent`. The test reads the declared graph and names the
FrameXML site per window, so a new window that reads the token and forgets
the edge fails with the line it reads it at.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
2026-10-18 12:05:47 -06:00
..