Skip to content

Aura Designer: a candidate-filter gate at the engine chokepoint, both container lanes - #252

Open
Maelareth wants to merge 2 commits into
DanderBot:mainfrom
Maelareth:feat/ad-candidate-filter-gate
Open

Aura Designer: a candidate-filter gate at the engine chokepoint, both container lanes#252
Maelareth wants to merge 2 commits into
DanderBot:mainfrom
Maelareth:feat/ad-candidate-filter-gate

Conversation

@Maelareth

Copy link
Copy Markdown

What

Engine capability that lets a feature darken its own aura displays on a switch, built for the Power Infusion Helper (follow-up PR) but written as general machinery. Two files: Frames/AuraContainer.lua, AuraDesigner/Factory.lua.

  • The chokepoint lanerecordCandidateFilters substitutes a populated match-nothing map when a config carries dfGate and the gate is shut (or the unit's role is excluded). Stored config is never touched: a rebuild produces something already gated, which removes the re-assert race a config-swapping design would carry against every future rebuild path (per the thread discussion and your sign-off on the chokepoint approach).
  • The slot lane — the route you sketched, with the corrections found while mapping: SlotHandle:_cf() derives the same substitution at read time; routed through the create-time declare, the tuning push, both latch re-parses, the recovery re-push, and the combat-exit replay (five stash reads, not four — the replay was the dangerous one). The identity-gate vulnerability recompute deliberately stays raw, or gated slots would leave the cine-latch population and return from a cutscene fail-open. The accessor is nil-faithful by construction — the recovery edge burns once and treats nil as nothing-to-repair.
  • Ownershipconfig.dfGate via one stampGate helper at every call site (your forget-one condition), self-stamps where the builder already holds the effect config, and a gateOwns predicate centralising which marks the gate owns. The sentinel-in-filter-data design is gone for the reasons that surfaced while mapping: profiles travel, the resolved maps are cached and shared, and debuff groups had nothing to mark.
  • Broadcast narrowed to owned entries in both registries (the native setters have no equality guard); lockdown defers through the standard regen replay. Role exclusion resolves per unit at the chokepoint, with an exported predicate so the sound path answers identically.

Why

Closes the intermittency you called out: the same placed indicator was gated when built out of combat (the Create fallback) and ungated when the slot path served it — "plainly missing is fine; intermittent is a bug report we'd never reproduce."

Testing

Field-verified across two group sessions and solo rounds on PTR: the gate darkening and reopening across every display family including a square built mid-combat arriving at combat's end already gated; role exclusion per unit; ordinary (non-gated) placed indicators regression-checked unchanged. Full history on lab thread d04fe999.

…, 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.
- 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.
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