Concept: Scan, Gather, Filter, Broadcast

Your persistent interact ability runs two of this plugin's tasks: a client-side scan that decides what to show, and a server-side granter that makes the options activatable.

  1. Scan - every scan-rate seconds the scan task traces (cursor or forward) and collects every ICrimsonInteractableTarget it finds, in priority order (closest / first hit).
  2. Gather - each target's GatherInteractionOptions fills the builder with its FCrimsonInteractionOptions.
  3. Filter - UpdateInteractableOptions resolves each option's ability spec and keeps only those whose CanActivateAbility passes, so unavailable options never show.
  4. Broadcast - if the option set changed, the task fires its InteractableObjectsChanged delegate with the surviving options in priority order. What happens next is your ability's job: store them and update your prompt.
  5. Grant - in parallel, the server-only GrantNearbyInteraction task overlaps the avatar and grants each option's InteractionAbilityToGrant and InteractionActionAbility, revoking grants for interactables that leave range.
Priority order is preserved
The delegate's array keeps the scan task's priority order, so index 0 is reliably the focused target. Change-detection sorts a separate snapshot, so a pure reorder does not re-fire the broadcast (no prompt flicker).
The filter is why the grant task is mandatory
An option whose granted/target ability cannot currently activate is silently dropped in the Filter step. If your prompt never appears, the usual cause is the grant task not running (it must be spawned on the server instance of the ability) or the handler ability failing CanActivateAbility (cost/cooldown/tag blocks).