--- a/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMaintenanceProbe.c
+++ b/addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeMaintenanceProbe.c
@@ -33,6 +33,9 @@
  protected SCR_RefuelAtSupportStationAction m_Action;
  protected BaseActionsManagerComponent m_Actions;
  protected UserActionContext m_Context;
+ protected PlayerController m_Controller;
+ protected SCR_InteractionHandlerComponent m_Interaction;
+ protected bool m_ReachDiagnosed;
  protected SCR_FuelSupportStationComponent m_Station;
  protected SCR_GadgetManagerComponent m_Gadgets;
  protected ref ERR_NativeMaintenanceMove m_Move;
@@ -105,7 +108,7 @@
   if (m_Can.FindComponent(SCR_FuelManagerComponent) != m_CanFuel) return false;
   if (m_Spare.FindComponent(SCR_FuelManagerComponent) != m_SpareFuel) return false;
   if (!m_Station || m_Can.FindComponent(SCR_FuelSupportStationComponent) != m_Station) return false;
-  if (!ContextValid()) return false;
+  if (!ContextValid() || !InteractionValid()) return false;
   if (m_ActionStarted && m_Action.GetActiveContext() != m_Context) return false;
   if (!Contains(m_Source, m_Spare) || !(Math.AbsFloat(m_SpareFuel.GetTotalFuel() - m_InitialSpare) <= 0.001)) return false;
   CarControllerComponent controller = CarControllerComponent.Cast(m_Vehicle.FindComponent(CarControllerComponent));
@@ -133,6 +136,7 @@
  protected bool ContextValid()
  {
   if (!m_Vehicle || !m_Action || m_Action.GetOwner() != m_Vehicle || !m_Actions || !m_Context) return false;
+  if (m_Action.WasDisabledByServer()) return false;
   if (m_Vehicle.FindComponent(BaseActionsManagerComponent) != m_Actions || !m_Actions.IsEnabled()) return false;
   array<UserActionContext> contexts = {}; m_Actions.GetContextList(contexts);
   if (contexts.Count() > 64 || !contexts.Contains(m_Context)) return false;
@@ -141,12 +145,43 @@
   float radius = m_Context.GetRadius();
   return ERR_ForceRules.FiniteVector(m_Context.GetOrigin()) && ERR_ForceRules.Finite(radius) && radius > 0 && radius <= 10;
  }
+ protected bool InteractionValid()
+ {
+  if (!GetGame() || !m_Controller || GetGame().GetPlayerController() != m_Controller) return false;
+  if (!m_Player || m_Controller.GetControlledEntity() != m_Player || !m_Interaction) return false;
+  if (m_Controller.FindComponent(SCR_InteractionHandlerComponent) != m_Interaction) return false;
+  return m_Interaction.GetControlledEntity() == m_Player;
+ }
+ protected float ActionRange()
+ {
+  if (!ContextValid() || !InteractionValid()) return -1;
+  float globalRange = m_Interaction.GetVisibilityRange();
+  if (!ERR_ForceRules.Finite(globalRange) || globalRange < 0) return -1;
+  float range = m_Context.GetVisibilityRange(globalRange);
+  if (!ERR_ForceRules.Finite(range) || range <= 0) return -1;
+  return range;
+ }
  protected bool AtAction()
  {
-  if (!m_Player || !ContextValid()) return false;
-  // Conservative sphere check also fits within a native capsule context.
-  if (vector.Distance(m_Player.GetOrigin(), m_Context.GetOrigin()) > Math.Min(3, m_Context.GetRadius())) return false;
+  float range = ActionRange();
+  if (range <= 0 || !ERR_ForceRules.FiniteVector(m_Player.GetOrigin())) return false;
+  // The native interaction handler uses this configured context/global range
+  // for distance retention. Context radius/height instead shape ray selection.
+  // This opt-in method fixture still does not prove UI selection or held input.
+  float distance = vector.Distance(m_Player.GetOrigin(), m_Context.GetOrigin());
+  if (!ERR_ForceRules.Finite(distance) || distance > range) return false;
   return m_Context.IsInVisibilityAngle(m_Player.GetOrigin());
+ }
+ protected void DiagnoseReach()
+ {
+  if (m_ReachDiagnosed) return;
+  m_ReachDiagnosed = true;
+  bool context = ContextValid();
+  bool interaction = InteractionValid();
+  PrintFormat("ERR MAINTENANCE REACH: state=%1 context=%2 interaction=%3 range=%4 started=%5", m_State, context, interaction, ActionRange(), m_ActionStarted);
+  if (!context || !m_Player) return;
+  PrintFormat("ERR MAINTENANCE GEOMETRY: player=%1 point=%2 distance=%3 angle=%4", m_Player.GetOrigin(), m_Context.GetOrigin(), vector.Distance(m_Player.GetOrigin(), m_Context.GetOrigin()), m_Context.IsInVisibilityAngle(m_Player.GetOrigin()));
+  PrintFormat("ERR MAINTENANCE CONTEXT: radius=%1 height=%2 capsule=%3 name=%4", m_Context.GetRadius(), m_Context.GetHeight(), m_Context.IsCapsule(), m_Context.GetContextName());
  }
  protected bool StartAction()
  {
@@ -207,7 +242,11 @@
   m_Inventory = InventoryStorageManagerComponent.Cast(m_Player.FindComponent(InventoryStorageManagerComponent));
   m_Fuel = SCR_FuelManagerComponent.Cast(m_Vehicle.FindComponent(SCR_FuelManagerComponent));
   m_Gadgets = SCR_GadgetManagerComponent.GetGadgetManager(m_Player);
-  if (!m_Source || !m_Inventory || !m_Fuel || !m_Gadgets) return false;
+  if (!m_Source || !m_Inventory || !m_Fuel || !m_Gadgets || !GetGame()) return false;
+  m_Controller = GetGame().GetPlayerController();
+  if (!m_Controller) return false;
+  m_Interaction = SCR_InteractionHandlerComponent.Cast(m_Controller.FindComponent(SCR_InteractionHandlerComponent));
+  if (!InteractionValid()) return false;
   array<IEntity> items = {}; ERR_Inventory.Items(m_Source, items);
   if (items.Count() > 128) return false;
   int cans;
@@ -273,7 +312,7 @@
   if (m_Stopped || m_State < 0) return -1;
   if (!Enabled() || !Replication.IsServer() || !m_Mode || m_Mode != ERR_GameMode.Get() || !m_Mode.Active()) { Stop(); return -1; }
   if (m_Started < 0) m_Started = now;
-  if (!WithinDeadline(m_Started, now)) { Check(false, "fixed refuel proof deadline"); return -1; }
+  if (!WithinDeadline(m_Started, now)) { DiagnoseReach(); Check(false, "fixed refuel proof deadline"); return -1; }
   if (m_State == 0)
   {
    if (!Check(Select(), "read-only selection pins two original five-litre cans and exact original parked UAZ action/tank")) return -1;
--- a/tests/test_native_maintenance_refuel.py
+++ b/tests/test_native_maintenance_refuel.py
@@ -48,6 +48,7 @@
 '''+within+r'''
 struct Probe {float m_Deadline=-1,m_Started=-1;bool failed=false;
  void Check(bool, const char*) {failed=true;}
+ void DiagnoseReach() {}
  int Tick(float now) {
 '''+clock+r'''
  return 0;
@@ -80,42 +81,56 @@
 # action's cached point initially equals its root; SetActiveContext alone does not
 # initialize it. Our double models that distinction instead of hiding the bug.
 import re
-methods='\n'.join(body(P,sig) for sig in ('protected bool ContextValid(', 'protected bool AtAction(', 'protected bool StartAction(', 'vector ApproachPosition('))
+methods='\n'.join(body(P,sig) for sig in ('protected bool ContextValid(', 'protected bool InteractionValid(', 'protected float ActionRange(', 'protected bool AtAction(', 'protected bool StartAction(', 'vector ApproachPosition(', 'protected void DiagnoseReach('))
 methods=methods.replace('protected ','').replace('null','nullptr').replace('array<','Array<')
 methods=methods.replace('Array<UserActionContext>','Array<UserActionContext*>').replace('Array<BaseUserAction>','Array<BaseUserAction*>')
 for ns in ('ERR_ForceRules','ERR_Actors','vector','Math'):methods=methods.replace(ns+'.',ns+'::')
-for obj in ('m_Vehicle','m_Action','m_Actions','m_Context','m_Player'):methods=re.sub(r'\b'+obj+r'\.',obj+'->',methods)
-methods=methods.replace('FindComponent(BaseActionsManagerComponent)','FindComponent()')
+for obj in ('m_Vehicle','m_Action','m_Actions','m_Context','m_Player','m_Controller','m_Interaction'):methods=re.sub(r'\b'+obj+r'\.',obj+'->',methods)
+methods=methods.replace('FindComponent(BaseActionsManagerComponent)','FindComponent()').replace('FindComponent(SCR_InteractionHandlerComponent)','FindComponent()').replace('GetGame().','GetGame()->')
 run(r'''
 #include <cassert>
 #include <vector>
 #include <algorithm>
 #include <cmath>
+#include <string>
 struct vector {float x=0,y=0,z=0;static const vector Zero;float&operator[](int i){return i==0?x:(i==1?y:z);}float LengthSq(){return x*x+y*y+z*z;}void Normalize(){float d=std::sqrt(LengthSq());x/=d;y/=d;z/=d;}vector operator-(vector b){return {x-b.x,y-b.y,z-b.z};}vector operator+(vector b){return {x+b.x,y+b.y,z+b.z};}vector operator*(float b){return {x*b,y*b,z*b};}static float Distance(vector a,vector b){return std::sqrt((a-b).LengthSq());}};
 const vector vector::Zero{};
 namespace ERR_Actors {vector Ground(vector p){return p;}}
 namespace Math {float Min(float a,float b){return std::min(a,b);}}
-namespace ERR_ForceRules {bool Finite(float v){return std::isfinite(v);}bool FiniteVector(vector v){return Finite(v.x);}}
+namespace ERR_ForceRules {bool Finite(float v){return std::isfinite(v);}bool FiniteVector(vector v){return Finite(v.x)&&Finite(v.y)&&Finite(v.z);}}
 template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;using std::vector<T>::operator=;int Count(){return this->size();}bool Contains(T t){return std::find(this->begin(),this->end(),t)!=this->end();}};
 struct BaseUserAction;struct UserActionContext;struct BaseActionsManagerComponent;
 struct Entity {vector pos;BaseActionsManagerComponent*manager=nullptr;vector GetOrigin(){return pos;}BaseActionsManagerComponent*FindComponent(){return manager;}};
-struct UserActionContext {vector pos{2};float radius=2;bool visible=true;Array<BaseUserAction*>actions;void GetActionsList(Array<BaseUserAction*>&out){out=actions;}vector GetOrigin(){return pos;}float GetRadius(){return radius;}bool IsInVisibilityAngle(vector){return visible;}};
+struct UserActionContext {vector pos{2};float radius=2,visibility=0,height=0;bool visible=true,capsule=false;Array<BaseUserAction*>actions;void GetActionsList(Array<BaseUserAction*>&out){out=actions;}vector GetOrigin(){return pos;}float GetRadius(){return radius;}float GetHeight(){return height;}bool IsCapsule(){return capsule;}std::string GetContextName(){return "fuel";}float GetVisibilityRange(float global){return std::max(global,visibility);}bool IsInVisibilityAngle(vector){return visible;}};
 struct BaseActionsManagerComponent {bool enabled=true;Array<UserActionContext*>contexts;bool IsEnabled(){return enabled;}void GetContextList(Array<UserActionContext*>&out){out=contexts;}};
-struct BaseUserAction {Entity*owner=nullptr;UserActionContext*context=nullptr;bool progressing=false,cacheOnStart=true;int set=0,started=0;vector cached;
- Entity*GetOwner(){return owner;}bool IsInProgress(){return progressing;}void SetActiveContext(UserActionContext*c){context=c;set++;}UserActionContext*GetActiveContext(){return context;}
+struct BaseUserAction {Entity*owner=nullptr;UserActionContext*context=nullptr;bool progressing=false,cacheOnStart=true,disabled=false;int set=0,started=0;vector cached;
+ Entity*GetOwner(){return owner;}bool WasDisabledByServer(){return disabled;}bool IsInProgress(){return progressing;}void SetActiveContext(UserActionContext*c){context=c;set++;}UserActionContext*GetActiveContext(){return context;}
  void OnActionStart(Entity*){assert(context&&set==1);started++;if(cacheOnStart)cached=context->GetOrigin();}vector GetWorldPositionAction(){return cached;}};
-struct Probe{Entity*m_Vehicle=nullptr,*m_Player=nullptr;BaseUserAction*m_Action=nullptr;BaseActionsManagerComponent*m_Actions=nullptr;UserActionContext*m_Context=nullptr;bool m_ActionStarted=false,held=true,allowed=true;int eligibility=0;
+struct SCR_InteractionHandlerComponent{Entity*actor=nullptr;float range=3;Entity*GetControlledEntity(){return actor;}float GetVisibilityRange(){return range;}};
+struct PlayerController{Entity*actor=nullptr;SCR_InteractionHandlerComponent*interaction=nullptr;Entity*GetControlledEntity(){return actor;}SCR_InteractionHandlerComponent*FindComponent(){return interaction;}};
+struct Game{PlayerController*controller=nullptr;PlayerController*GetPlayerController(){return controller;}}game;Game*currentGame=&game;Game*GetGame(){return currentGame;}
+int prints=0;template<class...Args>void PrintFormat(Args...){prints++;}
+struct Probe{PlayerController*m_Controller=nullptr;SCR_InteractionHandlerComponent*m_Interaction=nullptr;bool m_ReachDiagnosed=false;int m_State=3;Entity*m_Vehicle=nullptr,*m_Player=nullptr;BaseUserAction*m_Action=nullptr;BaseActionsManagerComponent*m_Actions=nullptr;UserActionContext*m_Context=nullptr;bool m_ActionStarted=false,held=true,allowed=true;int eligibility=0;
  bool Held(){return held;}bool ActionAllowed(){eligibility++;assert(m_ActionStarted&&m_Action->started==1&&m_Action->GetActiveContext()==m_Context);assert(vector::Distance(m_Action->GetWorldPositionAction(),m_Context->GetOrigin())<=.01);return allowed;}
 '''+methods+r'''
 };
-struct Fixture{Entity vehicle,player;BaseUserAction action;BaseActionsManagerComponent manager;UserActionContext context;Probe probe;
- Fixture(){vehicle.manager=&manager;player.pos={2};action.owner=&vehicle;manager.contexts={&context};context.actions={&action};probe.m_Vehicle=&vehicle;probe.m_Player=&player;probe.m_Action=&action;probe.m_Actions=&manager;probe.m_Context=&context;}};
+struct Fixture{PlayerController controller;SCR_InteractionHandlerComponent interaction;Entity vehicle,player;BaseUserAction action;BaseActionsManagerComponent manager;UserActionContext context;Probe probe;
+ Fixture(){currentGame=&game;game.controller=&controller;controller.actor=&player;controller.interaction=&interaction;interaction.actor=&player;probe.m_Controller=&controller;probe.m_Interaction=&interaction;vehicle.manager=&manager;player.pos={2};action.owner=&vehicle;manager.contexts={&context};context.actions={&action};probe.m_Vehicle=&vehicle;probe.m_Player=&player;probe.m_Action=&action;probe.m_Actions=&manager;probe.m_Context=&context;}};
 int main(){
  Fixture ok;assert(ok.action.GetWorldPositionAction().x==0&&ok.context.GetOrigin().x==2);assert(ok.probe.ContextValid()&&ok.probe.AtAction());assert(std::fabs(ok.probe.ApproachPosition().x-2.75f)<.001);assert(ok.probe.StartAction());assert(ok.action.started==1&&ok.action.set==1&&ok.probe.eligibility==1);assert(!ok.probe.StartAction()&&ok.action.started==1);
- for(int fault=0;fault<12;fault++){Fixture f;BaseActionsManagerComponent foreign;Entity other;UserActionContext otherContext;BaseUserAction otherAction;
- switch(fault){case 0:f.vehicle.manager=&foreign;break;case 1:f.manager.enabled=false;break;case 2:f.manager.contexts={&otherContext};break;case 3:f.context.actions={&otherAction};break;case 4:f.manager.contexts.resize(65,&f.context);break;case 5:f.context.actions.resize(65,&f.action);break;case 6:f.context.pos={NAN};break;case 7:f.context.radius=0;break;case 8:f.context.radius=11;break;case 9:f.action.owner=&other;break;case 10:f.probe.m_Context=nullptr;break;case 11:f.probe.m_Vehicle=nullptr;break;}
+ for(int fault=0;fault<13;fault++){Fixture f;BaseActionsManagerComponent foreign;Entity other;UserActionContext otherContext;BaseUserAction otherAction;
+ switch(fault){case 0:f.vehicle.manager=&foreign;break;case 1:f.manager.enabled=false;break;case 2:f.manager.contexts={&otherContext};break;case 3:f.context.actions={&otherAction};break;case 4:f.manager.contexts.resize(65,&f.context);break;case 5:f.context.actions.resize(65,&f.action);break;case 6:f.context.pos={NAN};break;case 7:f.context.radius=0;break;case 8:f.context.radius=11;break;case 9:f.action.owner=&other;break;case 10:f.probe.m_Context=nullptr;break;case 11:f.probe.m_Vehicle=nullptr;break;case 12:f.action.disabled=true;break;}
  assert(!f.probe.ContextValid()&&!f.probe.StartAction()&&!f.action.started&&!f.action.set);}
  for(int fault=0;fault<4;fault++){Fixture f;if(fault==0)f.probe.held=false;if(fault==1)f.player.pos={10};if(fault==2)f.context.visible=false;if(fault==3)f.action.progressing=true;assert(!f.probe.StartAction()&&!f.action.started&&!f.action.set);}
+ // Small elevated sphere/capsule is a target shape, not a feet reach limit.
+ for(bool capsule:{false,true}){Fixture f;f.context.radius=.2;f.context.height=2;f.context.capsule=capsule;f.context.pos={2,1.2,0};f.player.pos={2.5,0,0};assert(f.probe.AtAction()&&f.probe.StartAction());}
+ // Use exact configured global/context visibility, with no arbitrary3m ceiling.
+ Fixture configured;configured.interaction.range=2;configured.context.visibility=5;configured.player.pos={6.5,0,0};assert(configured.probe.ActionRange()==5&&configured.probe.AtAction());configured.player.pos={7.001f,0,0};assert(!configured.probe.AtAction());
+ for(int fault=0;fault<9;fault++){Fixture f;Entity other;PlayerController foreign;SCR_InteractionHandlerComponent foreignHandler;
+ switch(fault){case 0:game.controller=&foreign;break;case 1:f.controller.actor=&other;break;case 2:f.controller.interaction=&foreignHandler;break;case 3:f.interaction.actor=&other;break;case 4:currentGame=nullptr;break;case 5:f.probe.m_Controller=nullptr;break;case 6:f.probe.m_Interaction=nullptr;break;case 7:f.interaction.range=-1;break;case 8:f.interaction.range=NAN;break;}
+ assert(!f.probe.AtAction()&&!f.probe.StartAction()&&!f.action.started);}
+ Fixture diagnostic;prints=0;diagnostic.probe.DiagnoseReach();assert(prints==3);diagnostic.probe.DiagnoseReach();assert(prints==3);diagnostic.probe.m_Context=nullptr;diagnostic.probe.DiagnoseReach();assert(prints==3);
+ Fixture missingDiagnostic;missingDiagnostic.probe.m_Context=nullptr;prints=0;missingDiagnostic.probe.DiagnoseReach();missingDiagnostic.probe.DiagnoseReach();assert(prints==1);
  Fixture staleCache;staleCache.action.cacheOnStart=false;assert(!staleCache.probe.StartAction()&&staleCache.action.started==1&&staleCache.probe.eligibility==0&&staleCache.probe.m_ActionStarted);
  Fixture refusal;refusal.probe.allowed=false;assert(!refusal.probe.StartAction()&&refusal.action.started==1&&refusal.probe.m_ActionStarted);
 }
