This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: powersync-ios-wal-checkpoint-background-invariants

PowerSync SQLite WAL Invariant & Background Task Suspension Protocol

Mandates deterministic sync stream detachment and atomic SQLite WAL truncation checkpointing prior to iOS background task expiration. Prevents persistent -shm and -wal lockfile corruption caused by abrupt OS SIGKILL or suspension during in-flight CRDT mutations. Enforces atomic POSIX advisory lock cleanup across iOS application lifecycle transitions.

Prohibited Anti-Pattern: Unbounded CRDT Streaming and Missing WAL Checkpoint During iOS Background Suspension

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: PowerSync SQLite WAL Invariant & Background Task Suspension Protocol - Mandates deterministic sync stream detachment and atomic SQLite WAL truncation checkpointing prior to iOS background task expiration. Prevents persistent -shm and -wal lockfile corruption caused by abrupt OS SIGKILL or suspension during in-flight CRDT mutations. Enforces atomic POSIX advisory lock cleanup across iOS application lifecycle transitions.
globs: src/database/**/*.{ts,tsx}, src/powersync/**/*.{ts,tsx}, src/services/**/*.{ts,tsx}, ios/**/*.{swift,m}
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/powersync-ios-wal-checkpoint-background-invariants"
---

# PowerSync SQLite WAL Invariant & Background Task Suspension Protocol

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Unbounded CRDT Streaming and Missing WAL Checkpoint During iOS Background Suspension

## System Constraints
You are a Principal Mobile Architect enforcing strict SQLite WAL and PowerSync lifecycle invariants on iOS. When an iOS app transitions into the background, operating system watchdogs can freeze or terminate the process at sub-millisecond notice. If PowerSync is actively streaming CRDT batches or if SQLite holds active dirty pages in the Write-Ahead Log (WAL), SIGKILL or freeze events leave POSIX advisory locks and shared-memory (-shm) files in an indeterminate, corrupted state (e.g., persistent SQLITE_IOERR_SHORT_READ or SQLITE_BUSY lockouts on cold start). You must enforce mandatory background task registration, deterministic sync stream pausing, and explicit PRAGMA wal_checkpoint(TRUNCATE) execution before acknowledging background suspension.

## Strict Guidelines
- Engineers MUST ALWAYS acquire an OS background execution task (e.g., UIBackgroundTaskIdentifier via native bridge or equivalent) immediately when the app transitions to 'inactive' or 'background'.
- Engineers MUST ALWAYS disconnect or pause the PowerSync streaming client (await powersync.disconnectAndClear() or powersync.disconnect()) to cease incoming CRDT batch transactions before WAL checkpointing.
- Engineers MUST explicitly invoke 'PRAGMA wal_checkpoint(TRUNCATE)' on the underlying SQLite connection to commit all WAL frames into the primary database file and reset WAL headers.
- Engineers MUST NOT rely on SQLite default auto-checkpointing (SQLITE_DEFAULT_WAL_AUTOCHECKPOINT) during app backgrounding, as iOS can suspend the thread mid-checkpoint.
- Engineers MUST provide an expiration handler on the background task that safely cancels in-flight operations, rolls back open write transactions, and ends the task cleanly before iOS terminates the process.
- Engineers MUST ensure write mutexes are fully released and zero active transactions remain prior to calling endBackgroundTask.
- Components NEVER execute raw asynchronous SQLite writes during background suspension without wrapping the operation in an active background task token.

## Bad vs Good Implementations
### Naive AppState Listener vs. Deterministic WAL Truncation Lifecycle

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Fails to request an iOS background task token. PowerSync continues to process streaming network packets and apply CRDT checkpoints concurrently. When iOS suspends the app process mid-write or mid-checkpoint, lockfiles (-shm, -wal) are left orphaned, triggering SQLITE_BUSY or database corruption on subsequent launches.
```typescript
import { AppState, AppStateStatus } from 'react-native';
import { powersync } from './db';

// ANTI-PATTERN: PowerSync sync stream left active during background state.
// No background task requested. SQLite WAL left in dirty/uncommitted state.
// Sudden iOS termination causes -wal and -shm lockfile corruption.
export function registerLifecycleListeners() {
  AppState.addEventListener('change', (nextAppState: AppStateStatus) => {
    if (nextAppState === 'background') {
      console.log('App entered background, doing nothing...');
      // Streaming CRDT batches continue running asynchronously.
      // Process is suspended mid-transaction, leaving SQLite locks orphaned.
    }
  });
}
```

#### Production Standard (Correct)
> **Standard**: Acquires an iOS background execution token to secure CPU time before suspension. Gracefully disconnects the PowerSync streaming engine to drain pending transactions, then executes an explicit PRAGMA wal_checkpoint(TRUNCATE) within a managed transaction to flush all frames and reset the WAL header. Finally, releases the background task token cleanly.
```typescript
import { AppState, AppStateStatus, NativeModules } from 'react-native';
import { AbstractPowerSyncDatabase } from '@powersync/react-native';

interface BackgroundTaskBridge {
  beginBackgroundTask(name: string, onExpired: () => void): Promise<number>;
  endBackgroundTask(taskId: number): Promise<void>;
}

const { BackgroundTaskModule } = NativeModules as { BackgroundTaskModule: BackgroundTaskBridge };

export class DatabaseLifecycleManager {
  private isSuspending = false;

  constructor(private readonly db: AbstractPowerSyncDatabase) {}

  public register(): () => void {
    const subscription = AppState.addEventListener('change', this.handleAppStateChange.bind(this));
    return () => subscription.remove();
  }

  private async handleAppStateChange(nextState: AppStateStatus): Promise<void> {
    if (nextState !== 'background' && nextState !== 'inactive') {
      if (this.isSuspending) {
        this.isSuspending = false;
        await this.db.connect();
      }
      return;
    }

    if (this.isSuspending) return;
    this.isSuspending = true;

    let taskId = 0;
    try {
      taskId = await BackgroundTaskModule.beginBackgroundTask(
        'com.powersync.wal.checkpoint',
        () => {
          // Invariant: Handle watchdog expiration deterministically
          BackgroundTaskModule.endBackgroundTask(taskId);
        }
      );

      // 1. Halt incoming CRDT batches
      await this.db.disconnect();

      // 2. Ensure zero pending write transactions and force full WAL truncation
      await this.db.writeTransaction(async (tx) => {
        // Checkpoint all WAL frames back to main database and truncate log
        await tx.execute('PRAGMA wal_checkpoint(TRUNCATE);');
      });
    } catch (error) {
      console.error('Failed to cleanly checkpoint SQLite WAL before suspension:', error);
    } finally {
      if (taskId !== 0) {
        await BackgroundTaskModule.endBackgroundTask(taskId);
      }
    }
  }
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Recommended Agent Skills (askills.dev)

Ready-to-use executable skill functions tailored to this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: PowerSync SQLite WAL Invariant & Background Task Suspension Protocol

PowerSync SQLite WAL Invariant & Background Task Suspension Protocol defines an industrial-grade behavioral standard for mobile engineering. Mandates deterministic sync stream detachment and atomic SQLite WAL truncation checkpointing prior to iOS background task expiration. Prevents persistent -shm and -wal lockfile corruption caused by abrupt OS SIGKILL or suspension during in-flight CRDT mutations. Enforces atomic POSIX advisory lock cleanup across iOS application lifecycle transitions. 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: Unbounded CRDT Streaming and Missing WAL Checkpoint During iOS Background Suspension 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 DriftUnbounded CRDT Streaming and Missing WAL Checkpoint During iOS Background SuspensionCritical
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 acquire an OS background execution task (e.g., UIBackgroundTaskIdentifier via native bridge or equivalent) immediately when the app transitions to 'inactive' or 'background'.

Engineers MUST ALWAYS acquire an OS background execution task (e.g., UIBackgroundTaskIdentifier via native bridge or equivalent) immediately when the app transitions to 'inactive' or 'background'.

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 ALWAYS disconnect or pause the PowerSync streaming client (await powersync.disconnectAndClear() or powersync.disconnect()) to cease incoming CRDT batch transactions before WAL checkpointing.

Engineers MUST ALWAYS disconnect or pause the PowerSync streaming client (await powersync.disconnectAndClear() or powersync.disconnect()) to cease incoming CRDT batch transactions before WAL checkpointing.

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

Engineers MUST explicitly invoke 'PRAGMA wal_checkpoint(TRUNCATE)' on the underlying SQLite connection to commit all WAL frames into the primary database file and reset WAL headers.

Engineers MUST explicitly invoke 'PRAGMA wal_checkpoint(TRUNCATE)' on the underlying SQLite connection to commit all WAL frames into the primary database file and reset WAL headers.

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

Engineers MUST NOT rely on SQLite default auto-checkpointing (SQLITE_DEFAULT_WAL_AUTOCHECKPOINT) during app backgrounding, as iOS can suspend the thread mid-checkpoint.

Engineers MUST NOT rely on SQLite default auto-checkpointing (SQLITE_DEFAULT_WAL_AUTOCHECKPOINT) during app backgrounding, as iOS can suspend the thread mid-checkpoint.

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

Engineers MUST provide an expiration handler on the background task that safely cancels in-flight operations, rolls back open write transactions, and ends the task cleanly before iOS terminates the process.

Engineers MUST provide an expiration handler on the background task that safely cancels in-flight operations, rolls back open write transactions, and ends the task cleanly before iOS terminates the process.

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.
6

Engineers MUST ensure write mutexes are fully released and zero active transactions remain prior to calling endBackgroundTask.

Engineers MUST ensure write mutexes are fully released and zero active transactions remain prior to calling endBackgroundTask.

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

Components NEVER execute raw asynchronous SQLite writes during background suspension without wrapping the operation in an active background task token.

Components NEVER execute raw asynchronous SQLite writes during background suspension without wrapping the operation in an active background task token.

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 PowerSync SQLite WAL Invariant & Background Task Suspension Protocol critical for AI coding assistants?

Mandates deterministic sync stream detachment and atomic SQLite WAL truncation checkpointing prior to iOS background task expiration. Prevents persistent -shm and -wal lockfile corruption caused by abrupt OS SIGKILL or suspension during in-flight CRDT mutations. Enforces atomic POSIX advisory lock cleanup across iOS application lifecycle transitions. 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 (Unbounded CRDT Streaming and Missing WAL Checkpoint During iOS Background Suspension) 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

PowerSync