This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: capacitor7-geofence-power-throttle-invariant

Capacitor 7 Background Geofencing Hardware-Power Step-Down Invariant

Enforces battery-budget preservation in Capacitor 7 hybrid mobile applications by gating high-precision native geofence monitoring behind low-power step-down location providers. Continuous high-accuracy GNSS triggers OS watchdog terminations (iOS Energy Log kills, Android vitals excessive wake lock evictions) unless step-down coalescing is systematically implemented.

Prohibited Anti-Pattern: Continuous High-Accuracy GNSS Polling and Ungated Native Geofence Registration Causing OS Battery Eviction

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Capacitor 7 Background Geofencing Hardware-Power Step-Down Invariant - Enforces battery-budget preservation in Capacitor 7 hybrid mobile applications by gating high-precision native geofence monitoring behind low-power step-down location providers. Continuous high-accuracy GNSS triggers OS watchdog terminations (iOS Energy Log kills, Android vitals excessive wake lock evictions) unless step-down coalescing is systematically implemented.
globs: src/**/*.{ts,tsx}, android/app/src/main/java/**/*.kt, ios/App/App/**/*.swift
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/capacitor7-geofence-power-throttle-invariant"
---

# Capacitor 7 Background Geofencing Hardware-Power Step-Down Invariant

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Continuous High-Accuracy GNSS Polling and Ungated Native Geofence Registration Causing OS Battery Eviction

## System Constraints
You are a Principal Mobile Architect enforcing the Capacitor 7 Background Geofencing Hardware-Power Throttle Invariant. Modern mobile operating systems (iOS 17+ and Android 14+) enforce strict runtime battery budgets; applications exceeding background hardware location quotas face non-catchable SIGKILL terminations or severe throttle penalties. You must mandate that high-precision hardware geofences and fine-grained GNSS sampling are lazily instantiated only when low-power coarse providers (significant-change monitoring on iOS, passive/cell-tower fused location on Android) detect proximity within an adaptive step-down buffer. Ensure all bridge invocations are throttled, coalesced, and resilient to OS-level background eviction.

## Strict Guidelines
- Engineers MUST ALWAYS implement a tiered location resolution state machine (Dormant -> Significant Change / Coarse Horizon -> Hardware Geofence Active) rather than registering high-accuracy listeners indefinitely.
- Engineers MUST NOT invoke `Geolocation.watchPosition` with `enableHighAccuracy: true` in background service contexts without an explicit, deterministic timeout and hysteresis margin.
- Services MUST coalesce and batch bridge transition events before sending them across the Capacitor JS-to-native boundary to prevent waking the JavaScript thread on every raw native hardware tick.
- Code SHOULD calculate great-circle distance (Haversine formula) against active fence boundaries to dynamically tune native update intervals based on velocity and physical proximity.
- Components NEVER instantiate background geofence listeners without validating native permission statuses for both background access (`locationAlways`) and battery optimization exemption status on Android.

## Bad vs Good Implementations
### Naive Continuous High-Accuracy Geofence Polling vs. Adaptive Step-Down Geofencing Engine

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: This implementation uses continuous high-accuracy hardware polling without power-aware tiers. On iOS, continuous GPS in background results in Watchdog energy terminations. On Android, running continuous GNSS without battery optimization triggers vitals-kill thresholds within minutes.
```typescript
import { Plugins } from '@capacitor/core';
const { Geolocation } = Plugins;

// ANTI-PATTERN: Indefinite high-accuracy background polling destroys battery
// and causes Android Background Execution Limits / iOS Watchdog terminations.
export class NaiveGeofenceTracker {
  private targetLat = 37.7749;
  private targetLng = -122.4194;
  private radiusMeters = 200;

  public startTracking(): void {
    Geolocation.watchPosition(
      {
        enableHighAccuracy: true, // Forces GNSS hardware active continuously
        timeout: 10000,
        maximumAge: 0
      },
      (position: any) => {
        if (!position) return;
        const distance = this.getDistance(
          position.coords.latitude,
          position.coords.longitude,
          this.targetLat,
          this.targetLng
        );
        if (distance <= this.radiusMeters) {
          console.log('Entered geofence!');
        }
      }
    );
  }

  private getDistance(lat1: number, lon1: number, lat2: number, lon2: number): number {
    return Math.hypot(lat2 - lat1, lon2 - lon1) * 111000;
  }
}
```

#### Production Standard (Correct)
> **Standard**: Implements an OS-adherent step-down state machine. The application registers significant-change monitoring (cell-tower/Wi-Fi powered, zero continuous GNSS drain). High-precision hardware geofencing is lazily configured only when the client crosses inside the dynamic 2000-meter proximity horizon, and stepped down immediately once outside.
```typescript
import { registerPlugin, PluginListenerHandle } from '@capacitor/core';

interface LatLng { latitude: number; longitude: number; }
interface GeofenceConfig { id: string; center: LatLng; radiusMeters: number; }
enum TrackingState { DORMANT = 'DORMANT', HORIZON = 'HORIZON', HIGH_PRECISION = 'HIGH_PRECISION' }

export interface LowPowerLocationPlugin {
  startSignificantLocationMonitoring(): Promise<void>;
  stopSignificantLocationMonitoring(): Promise<void>;
  registerNativeGeofence(options: { id: string; latitude: number; longitude: number; radius: number }): Promise<void>;
  clearNativeGeofence(options: { id: string }): Promise<void>;
  addListener(eventName: 'onSignificantChange', listenerFunc: (pos: LatLng) => void): Promise<PluginListenerHandle>;
  addListener(eventName: 'onGeofenceTransition', listenerFunc: (event: { id: string; type: 'ENTER' | 'EXIT' }) => void): Promise<PluginListenerHandle>;
}

const LowPowerLocation = registerPlugin<LowPowerLocationPlugin>('LowPowerLocation');

export class CoalescedGeofenceEngine {
  private state: TrackingState = TrackingState.DORMANT;
  private readonly PROXIMITY_HORIZON_METERS = 2000;
  private sigChangeHandle: PluginListenerHandle | null = null;
  private geofenceHandle: PluginListenerHandle | null = null;

  constructor(private readonly fence: GeofenceConfig) {}

  public async initialize(): Promise<void> {
    // Step 1: Default to low-power significant change provider (Cell/Wi-Fi step-down)
    this.state = TrackingState.HORIZON;
    this.sigChangeHandle = await LowPowerLocation.addListener('onSignificantChange', (pos) => {
      this.evaluateHorizonStep(pos);
    });
    await LowPowerLocation.startSignificantLocationMonitoring();
  }

  private async evaluateHorizonStep(currentPos: LatLng): Promise<void> {
    const distance = this.haversineDistance(currentPos, this.fence.center);

    if (distance <= this.PROXIMITY_HORIZON_METERS && this.state !== TrackingState.HIGH_PRECISION) {
      // Step-up to native OS-managed hardware geofence only when within safety buffer
      this.state = TrackingState.HIGH_PRECISION;
      this.geofenceHandle = await LowPowerLocation.addListener('onGeofenceTransition', (ev) => {
        if (ev.id === this.fence.id && ev.type === 'ENTER') {
          this.handleGeofenceTrigger();
        }
      });
      await LowPowerLocation.registerNativeGeofence({
        id: this.fence.id,
        latitude: this.fence.center.latitude,
        longitude: this.fence.center.longitude,
        radius: this.fence.radiusMeters
      });
    } else if (distance > this.PROXIMITY_HORIZON_METERS && this.state === TrackingState.HIGH_PRECISION) {
      // Step-down back to low-power coarse tracking
      await this.tearDownHighPrecision();
      this.state = TrackingState.HORIZON;
    }
  }

  private async handleGeofenceTrigger(): Promise<void> {
    // Coalesce and process the transition payload without waking JS continuously
    await this.tearDownHighPrecision();
    this.state = TrackingState.DORMANT;
  }

  private async tearDownHighPrecision(): Promise<void> {
    if (this.geofenceHandle) {
      await this.geofenceHandle.remove();
      this.geofenceHandle = null;
    }
    await LowPowerLocation.clearNativeGeofence({ id: this.fence.id });
  }

  private haversineDistance(c1: LatLng, c2: LatLng): number {
    const R = 6371e3; // Earth radius in meters
    const dLat = ((c2.latitude - c1.latitude) * Math.PI) / 180;
    const dLon = ((c2.longitude - c1.longitude) * Math.PI) / 180;
    const a =
      Math.sin(dLat / 2) * Math.sin(dLat / 2) +
      Math.cos((c1.latitude * Math.PI) / 180) *
        Math.cos((c2.latitude * Math.PI) / 180) *
        Math.sin(dLon / 2) *
        Math.sin(dLon / 2);
    return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  }
}
```

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Capacitor 7 Background Geofencing Hardware-Power Step-Down Invariant

Capacitor 7 Background Geofencing Hardware-Power Step-Down Invariant defines an industrial-grade behavioral standard for mobile engineering. Enforces battery-budget preservation in Capacitor 7 hybrid mobile applications by gating high-precision native geofence monitoring behind low-power step-down location providers. Continuous high-accuracy GNSS triggers OS watchdog terminations (iOS Energy Log kills, Android vitals excessive wake lock evictions) unless step-down coalescing is systematically implemented. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Continuous High-Accuracy GNSS Polling and Ungated Native Geofence Registration Causing OS Battery Eviction Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftContinuous High-Accuracy GNSS Polling and Ungated Native Geofence Registration Causing OS Battery EvictionCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS implement a tiered location resolution state machine (Dormant -> Significant Change / Coarse Horizon -> Hardware Geofence Active) rather than registering high-accuracy listeners indefinitely.

Engineers MUST ALWAYS implement a tiered location resolution state machine (Dormant -> Significant Change / Coarse Horizon -> Hardware Geofence Active) rather than registering high-accuracy listeners indefinitely.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT invoke `Geolocation.watchPosition` with `enableHighAccuracy

Engineers MUST NOT invoke `Geolocation.watchPosition` with `enableHighAccuracy: true` in background service contexts without an explicit, deterministic timeout and hysteresis margin.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Services MUST coalesce and batch bridge transition events before sending them across the Capacitor JS-to-native boundary to prevent waking the JavaScript thread on every raw native hardware tick.

Services MUST coalesce and batch bridge transition events before sending them across the Capacitor JS-to-native boundary to prevent waking the JavaScript thread on every raw native hardware tick.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Code SHOULD calculate great-circle distance (Haversine formula) against active fence boundaries to dynamically tune native update intervals based on velocity and physical proximity.

Code SHOULD calculate great-circle distance (Haversine formula) against active fence boundaries to dynamically tune native update intervals based on velocity and physical proximity.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Components NEVER instantiate background geofence listeners without validating native permission statuses for both background access (`locationAlways`) and battery optimization exemption status on Android.

Components NEVER instantiate background geofence listeners without validating native permission statuses for both background access (`locationAlways`) and battery optimization exemption status on Android.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is Capacitor 7 Background Geofencing Hardware-Power Step-Down Invariant critical for AI coding assistants?

Enforces battery-budget preservation in Capacitor 7 hybrid mobile applications by gating high-precision native geofence monitoring behind low-power step-down location providers. Continuous high-accuracy GNSS triggers OS watchdog terminations (iOS Energy Log kills, Android vitals excessive wake lock evictions) unless step-down coalescing is systematically implemented. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Continuous High-Accuracy GNSS Polling and Ungated Native Geofence Registration Causing OS Battery Eviction) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

Related MOBILE Rules

View all rules →
1 Rule in Stack

Capacitor