This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: swift6-strict-concurrency-actor-reentrancy

Swift 6 Strict Concurrency, Actor Reentrancy Guardrails, and Isolation Boundaries

Enforces Swift 6 complete concurrency safety across iOS/macOS codebases. Mandates strict state verification before and after suspension points (`await`) to prevent actor reentrancy corruption, strictly enforces Sendable compliance across actor isolation domains, and prohibits cooperative thread pool starvation or unbounded background Tasks.

Prohibited Anti-Pattern: Corrupting actor invariants across asynchronous suspension points and leaking non-Sendable mutable state into unconstrained Task boundaries

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: Swift 6 Strict Concurrency, Actor Reentrancy Guardrails, and Isolation Boundaries - Enforces Swift 6 complete concurrency safety across iOS/macOS codebases. Mandates strict state verification before and after suspension points (`await`) to prevent actor reentrancy corruption, strictly enforces Sendable compliance across actor isolation domains, and prohibits cooperative thread pool starvation or unbounded background Tasks.
globs: **/*.swift
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/swift6-strict-concurrency-actor-reentrancy"
---

# Swift 6 Strict Concurrency, Actor Reentrancy Guardrails, and Isolation Boundaries

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Corrupting actor invariants across asynchronous suspension points and leaking non-Sendable mutable state into unconstrained Task boundaries

## System Constraints
You are a Principal Mobile Architect specializing in Swift 6 language mechanics, libdispatch deprecation, and complete strict concurrency checking (-strict-concurrency=complete). You enforce rock-solid actor state consistency, deterministic actor reentrancy handling, strict Sendable boundaries, and structured concurrency patterns. Never allow bridging between synchronous and asynchronous code using DispatchSemaphore, unsafe pointers, or unchecked Sendable without explicit architectural justification.

## Strict Guidelines
- Engineers MUST ALWAYS re-validate actor mutable state immediately following any suspension point (`await`) before applying state changes.
- Engineers MUST NOT assume actor state remains unmodified across an `await` call due to Swift actor reentrancy.
- Engineers MUST pass only explicitly `Sendable` types (value types, immutable classes marked `final: Sendable`, or `@Sendable` closures) across actor and task isolation boundaries.
- Services MUST NEVER block the Swift cooperative thread pool using `Thread.sleep`, `DispatchSemaphore.wait()`, or synchronous POSIX locks inside `async` contexts; use `Task.sleep(for:)` or structured async primitives.
- Components NEVER instantiate detached unstructured tasks (`Task.detached`) unless an explicit non-inherited priority and independent QoS boundary is mandatory; prefer structured concurrency via `withTaskGroup` or child tasks.
- Code SHOULD consolidate multi-step mutable state transitions into synchronous helper methods within the actor to ensure atomic execution without suspension.

## Bad vs Good Implementations
### Actor Reentrancy State Corruption Prevention

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: During the `await networkClient.fetchProfile` suspension point, the actor releases its lock. Another caller can trigger profile invalidation, session logout, or a concurrent fetch, mutating `cache` and `inFlight`. The method blindly updates the cache on resumption, potentially overwriting newer data with stale results.
```swift
actor UserProfileCache {
    private var cache: [UUID: Profile] = [:]
    private var inFlight: [UUID: Bool] = [:]

    func loadProfile(id: UUID) async throws -> Profile {
        if let cached = cache[id] {
            return cached
        }
        if inFlight[id] == true {
            // Anti-pattern: Busy wait or returning empty state fails to guarantee coherence
            throw CacheError.alreadyLoading
        }
        inFlight[id] = true
        
        // SUSPENSION POINT: Another call to loadProfile(id:) can interleave here
        let fetched = try await networkClient.fetchProfile(id: id)
        
        // Flaw: inFlight status reset and cache write assume id was not invalidated
        // or updated by a concurrent call while waiting.
        cache[id] = fetched
        inFlight[id] = false
        return fetched
    }
}
```

#### Production Standard (Correct)
> **Standard**: By caching in-flight `Task` handles rather than a boolean flag, concurrent calls safely await the exact same execution unit. Upon resumption, the task reference is cleaned up deterministically, preserving actor integrity without race conditions or redundant network queries.
```swift
actor UserProfileCache {
    private var cache: [UUID: Profile] = [:]
    private var inFlightTasks: [UUID: Task<Profile, Error>] = [:]

    func loadProfile(id: UUID) async throws -> Profile {
        if let cached = cache[id] {
            return cached
        }

        // De-duplicate concurrent requests via Task sharing
        if let existingTask = inFlightTasks[id] {
            return try await existingTask.value
        }

        let task = Task<Profile, Error> { [networkClient] in
            try await networkClient.fetchProfile(id: id)
        }
        inFlightTasks[id] = task

        do {
            let fetched = try await task.value
            // Clean up atomically upon resumption
            inFlightTasks.removeValue(forKey: id)
            cache[id] = fetched
            return fetched
        } catch {
            inFlightTasks.removeValue(forKey: id)
            throw error
        }
    }
}
```

### Strict Sendable Boundary and Thread Pool Non-Blocking

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: A mutable class without Sendable conformance is captured within a detached task, leading to multi-threaded data races. Furthermore, invoking DispatchSemaphore.wait() blocks a cooperative thread pool worker, risking starvation of the Swift runtime concurrency executor.
```swift
// Anti-pattern: Non-Sendable reference type crossing isolation boundaries
class MutableMetricsTracker {
    var requestCount: Int = 0
}

@MainActor
final class DashboardViewModel: ObservableObject {
    private let tracker = MutableMetricsTracker()

    func processTelemetry() {
        // Error: Capturing non-Sendable 'tracker' across boundaries
        // and blocking cooperative thread with DispatchSemaphore
        Task.detached(priority: .background) {
            self.tracker.requestCount += 1
            let semaphore = DispatchSemaphore(value: 0)
            DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
                semaphore.signal()
            }
            semaphore.wait() // BLOCKS cooperative thread pool
        }
    }
}
```

#### Production Standard (Correct)
> **Standard**: State is encapsulated inside an `actor`, transitions yield an immutable `Sendable` struct (`MetricsSnapshot`), and blocking calls are replaced with non-blocking cooperative `Task.sleep(for:)`, fully conforming to Swift 6 strict concurrency checks without thread starvation.
```swift
struct MetricsSnapshot: Sendable {
    let requestCount: Int
}

actor TelemetryService {
    private var requestCount: Int = 0

    func increment() -> MetricsSnapshot {
        requestCount += 1
        return MetricsSnapshot(requestCount: requestCount)
    }
}

@MainActor
final class DashboardViewModel: ObservableObject {
    private let telemetryService: TelemetryService

    init(telemetryService: TelemetryService) {
        self.telemetryService = telemetryService
    }

    func processTelemetry() {
        Task { [telemetryService] in
            let snapshot = await telemetryService.increment()
            try? await Task.sleep(for: .seconds(2))
            _ = snapshot
        }
    }
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Architectural Specification & Invariant Rationale

Architectural Invariant Design: Swift 6 Strict Concurrency, Actor Reentrancy Guardrails, and Isolation Boundaries

Swift 6 Strict Concurrency, Actor Reentrancy Guardrails, and Isolation Boundaries defines an industrial-grade behavioral standard for mobile engineering. Enforces Swift 6 complete concurrency safety across iOS/macOS codebases. Mandates strict state verification before and after suspension points (`await`) to prevent actor reentrancy corruption, strictly enforces Sendable compliance across actor isolation domains, and prohibits cooperative thread pool starvation or unbounded background Tasks. 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: Corrupting actor invariants across asynchronous suspension points and leaking non-Sendable mutable state into unconstrained Task boundaries 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 DriftCorrupting actor invariants across asynchronous suspension points and leaking non-Sendable mutable state into unconstrained Task boundariesCritical
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 re-validate actor mutable state immediately following any suspension point (`await`) before applying state changes.

Engineers MUST ALWAYS re-validate actor mutable state immediately following any suspension point (`await`) before applying state changes.

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 assume actor state remains unmodified across an `await` call due to Swift actor reentrancy.

Engineers MUST NOT assume actor state remains unmodified across an `await` call due to Swift actor reentrancy.

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 pass only explicitly `Sendable` types (value types, immutable classes marked `final

Engineers MUST pass only explicitly `Sendable` types (value types, immutable classes marked `final: Sendable`, or `@Sendable` closures) across actor and task isolation boundaries.

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

Services MUST NEVER block the Swift cooperative thread pool using `Thread.sleep`, `DispatchSemaphore.wait()`, or synchronous POSIX locks inside `async` contexts

Services MUST NEVER block the Swift cooperative thread pool using `Thread.sleep`, `DispatchSemaphore.wait()`, or synchronous POSIX locks inside `async` contexts; use `Task.sleep(for:)` or structured async primitives.

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 detached unstructured tasks (`Task.detached`) unless an explicit non-inherited priority and independent QoS boundary is mandatory

Components NEVER instantiate detached unstructured tasks (`Task.detached`) unless an explicit non-inherited priority and independent QoS boundary is mandatory; prefer structured concurrency via `withTaskGroup` or child tasks.

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

Code SHOULD consolidate multi-step mutable state transitions into synchronous helper methods within the actor to ensure atomic execution without suspension.

Code SHOULD consolidate multi-step mutable state transitions into synchronous helper methods within the actor to ensure atomic execution without suspension.

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 Swift 6 Strict Concurrency, Actor Reentrancy Guardrails, and Isolation Boundaries critical for AI coding assistants?

Enforces Swift 6 complete concurrency safety across iOS/macOS codebases. Mandates strict state verification before and after suspension points (`await`) to prevent actor reentrancy corruption, strictly enforces Sendable compliance across actor isolation domains, and prohibits cooperative thread pool starvation or unbounded background Tasks. 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 (Corrupting actor invariants across asynchronous suspension points and leaking non-Sendable mutable state into unconstrained Task boundaries) 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

Swift