Skip to content

Aura Designer: the Power Infusion Helper - #253

Open
Maelareth wants to merge 5 commits into
DanderBot:mainfrom
Maelareth:feat/pi-helper
Open

Aura Designer: the Power Infusion Helper#253
Maelareth wants to merge 5 commits into
DanderBot:mainfrom
Maelareth:feat/pi-helper

Conversation

@Maelareth

Copy link
Copy Markdown

What

The Power Infusion Helper: a priest-only recipe in the Aura Designer (Other Buffs tab). One click marks the group members worth infusing; everything it shows goes dark while the player's own Power Infusion is on cooldown, with a switch to keep it always on. CHANGELOG entry included.

Three signals, each an ordinary frame-level effect movable between the five colour surfaces, a placed Icon or Square, or None — plus per-signal icon rows (Filter Groups showing one icon per matching aura). Sound rides the gate's edges and roster changes, per-unit and class-narrowed, never for the player's own unit and never for an excluded role. Settings live once on the helper and are applied by the resident half on login, profile switch and every panel change — correct with the settings panel never opened.

Depends on #252 (this branch stacks on it; review the second commit only — the first is #252 verbatim). This is the feature that stamps config.dfGate.

⚠ One design decision taken on our side, flagged for your eye

The already-infused signal is exempt from the gate (gateOwns skips it). Field history: the signal had never rendered anywhere — its caster rule filtered out the priest's own casts (and PI on a teammate is always the priest's own cast), and behind that, casting PI is what starts the cooldown that darkens the helper, so the mark turned on and was hidden in the same instant, structurally. Its caster rule is now inverted and it ignores the gate: the violet shows where the buff went for its duration while everything else stays hidden. The exemption also skips role exclusion — "genuinely has Power Infusion" is true whatever the role. Full reasoning in batch 5 on the thread; if you'd draw the line elsewhere, it's one small isolated change.

Testing

Two group sessions (thanks again to Aphoex) plus extensive solo rounds on PTR and retail: every signal on every surface, the strong window's two-condition judgement firing only on both halves, icons-only setups end to end, cold start, profile lifecycle (incl. switch-away teardown of sound registrations), mid-combat deferred builds arriving gated, role exclusion on visuals and sound, rejoiner arming, leak check on removal. The one thing no session can reach is raid-scale cost on the gate edge — flagged for the feature's first raid night. Full history and the open items (15–21) on lab thread d04fe999.

Maelareth added 5 commits August 27, 2026 11:09
…, both container lanes

Adds the machinery that lets a feature darken its own aura displays on a
switch - built for the Power Infusion Helper (following PR) but written as
engine capability.

The chokepoint: every engine write of candidate filters funnels through one
of two lanes. Group/overlay/row containers pass recordCandidateFilters, which
substitutes a populated match-nothing map when the config carries the
ownership mark and the gate is shut (or the unit's role is excluded). Stored
config is never touched: a rebuild produces something already gated rather
than something corrected afterwards, which removes the re-assert race a
config-swapping design would carry against every future rebuild path.

The slot lane: placed indicators (AcquireSlot) never passed that funnel -
their map went straight from config into the engine at six sites, so a gated
placed indicator was gated when it fell back to the per-indicator container
(in combat) and ungated when the slot path served it. SlotHandle:_cf()
derives the same substitution at read time; routed through it are the
create-time declare, the tuning push, the cine and death latch re-parses, the
recovery re-push, and the combat-exit replay. The one deliberate exception is
the identity-gate vulnerability recompute, which must see the real selection
or gated slots would leave the cinematic-latch population and return from a
cutscene fail-open. The accessor is nil-faithful: never nil for a real
selection (the recovery edge burns once and treats nil as nothing-to-repair),
never a value for a nil one.

Ownership is config.dfGate, stamped by whoever builds a config - one
stampGate helper at every call site so a missed site reads as an absent line
in a known list, plus self-stamps in the builders that already hold the
effect config. A gateOwns predicate centralises which marks the gate owns.
An earlier design carried a synthetic spell id in real filter data; rejected
because profiles travel and get decoded, the resolved maps are cached and
shared between consumers, and debuff groups carry no config-wide candidate
set to mark.

The broadcast walks both registries narrowed to owned entries - the native
setters have no equality guard, so an unnarrowed walk would re-parse every
container in the addon per flip. In lockdown the slot lane defers through the
standard regen replay. Role exclusion resolves per unit at the same
chokepoint (player's own role from spec, others from the group, failing open
on NONE), with an exported predicate so non-container consumers (sound) can
give the same answer.
A priest-only recipe in the Aura Designer, added from the Other Buffs tab.
One click marks the group members worth infusing; everything it shows goes
dark while the player's own Power Infusion is on cooldown (with a switch to
keep it always on), so it only speaks up when they can act on it.

Three signals, each an ordinary frame-level effect the user can move between
Border, Health Bar, Background, the two text colours, a placed Icon or
Square, or None:

- Big cooldown: a curated offensive-cooldown list (plus four offensive
  racials), others-only so a group member's own press lights their frame.
- Big cooldown with a trinket or potion: the same list AND an amplifier
  (combat potions / on-use trinkets, opt-in ticks) via a two-group condition
  chain - the one signal that judges a combination, so the one that can only
  be a colour.
- Already has active Power Infusion: marks where the buff went. Its caster
  rule is inverted (PI on a teammate is always the priest's own cast) and it
  is exempt from the gate - its subject is created by the gate's own trigger,
  so gated it could never show. Both were field-found: the signal had never
  rendered anywhere until they were fixed.

Icons: each signal can also render as a Filter Group - one icon per matching
aura, the aura's own artwork. Cooldowns and amplifiers share a row
(others-only); the infused icon is its own one-icon group with the opposite
caster rule. State derives from the groups' own selections, so hand-editing
them on the Layout Groups tab and the panel ticks can never disagree.

The gate: cast-driven shut (the only unambiguous "it just went down"), flag-
driven reopen with an unreadable state resolved from charges, a 0.5s poll
only while dark (nothing fires when a cooldown quietly expires), and a
diagnostic at /df debug pi showing intent, the chokepoint's answer, per-frame
sound registrations and live gated containers. Events register only while a
helper exists, so non-priests pay nothing.

Sound: per-unit, class-narrowed registrations riding the gate's edges plus
roster changes (debounced) - never for the player's own unit, and never for
a role the exclusions hide, so a cue cannot fire for a unit nothing marks.
Role exclusion (tanks and healers by default, untickable) resolves at the
container chokepoint per unit.

Settings live on the helper, not per effect: one copy of the roles, the
amplifiers, the gate switch and the sound, applied by the resident half on
login, profile switch, and every panel change - the addon stays correct with
the settings panel never opened. Removing the helper removes everything it
built; the shared spell lists are only deleted when no helper mark remains
in either mode.

Field-verified across two group sessions and extensive solo rounds: every
signal, every surface, the cold start, the profile lifecycle, mid-combat
deferred builds arriving gated, and the leak check.

Depends on the candidate-filter gate machinery (previous PR): this is the
feature that stamps config.dfGate.
- The gate broadcast skips parked slots: a parked slot renders nothing, so
  pushing candidates at it is pure work, and it stays in the registry by
  necessity because Restore has to find it again. Restore now re-pushes
  candidates through the accessor, so a gate edge that flipped while the
  slot was parked is picked up on un-park rather than lost.
- The container debug dump reports the raw selection instead of the gated
  one. It read through the gating accessor, so a gated row logged the dead
  match-nothing placeholder rather than the user's real filter - on the one
  diagnostic line most likely to be read while debugging that exact gate.
- The gate's combat-exit backstop registers its five events only while a
  consumer exists, matching the pattern its sibling watcher already used.
  Driven by a single "does a consumer exist" test so the two registrations
  cannot disagree.
…ive more

- BLOCKER: the signal's display name was written onto the effect config,
  which lives in the profile - a translated string turned into saved data.
  Built on an English client and switched to German, the stored row name
  stays English while the surface dropdown resolves live and shows German.
  The mark is the stored truth; the label derives from it at render, through
  one exported resolver so the panel and the effects list cannot disagree.
  Placed rows gain the same derivation, which they never had.
- The secret guard was defeated by its own evaluation order: `and` runs left
  to right, so the nil comparison ran before the check meant to prevent it,
  and comparing against a sealed value is what throws.
- Refusals reach the debug log; they returned a reason nothing read, so a
  failure looked exactly like a dead control.
- The surface dropdown greys in place instead of vanishing - it belongs to a
  feature toggle. The Trinkets and Potions group stays hidden, with its
  existing rationale.
- Unticking the last signal re-derives the way Remove does, and "does a
  helper exist" is now one question answered from the marks - the same
  derivation the panel uses. It was two: the engine counted a recorded list
  id that outlives the signals, so emptying the helper left its events
  registered and its sound armed while the panel correctly showed it gone.
- The Filter Designer button uses the shared disabled treatment, and the
  changelog entry is trimmed to four sentences.
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.

1 participant