This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
mobilecritical PriorityID: kmp-datastore-proto-backward-compatibility-guardrail

KMP Proto DataStore Schema Backward Compatibility & Native Concurrency Invariant

Mandates rigid Protobuf field reservation and deterministic serialization guards for Kotlin Multiplatform Core DataStore implementations across Android ART and iOS Swift 6 concurrency domains. Prevents silent deserialization corruption, race conditions across native runtime boundaries, and runtime decode crashes caused by field renumbering or divergent schema evolution.

Prohibited Anti-Pattern: Destructive Proto Schema Field Mutation and Non-Thread-Safe Multiplatform DataStore Deserialization

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: KMP Proto DataStore Schema Backward Compatibility & Native Concurrency Invariant - Mandates rigid Protobuf field reservation and deterministic serialization guards for Kotlin Multiplatform Core DataStore implementations across Android ART and iOS Swift 6 concurrency domains. Prevents silent deserialization corruption, race conditions across native runtime boundaries, and runtime decode crashes caused by field renumbering or divergent schema evolution.
globs: **/*.proto, **/commonMain/**/datastore/**/*.kt, **/iosMain/**/datastore/**/*.kt, **/androidMain/**/datastore/**/*.kt
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/kmp-datastore-proto-backward-compatibility-guardrail"
---

# KMP Proto DataStore Schema Backward Compatibility & Native Concurrency Invariant

> **Severity**: CRITICAL | **Category**: mobile
> **Anti-Pattern Warning**: Destructive Proto Schema Field Mutation and Non-Thread-Safe Multiplatform DataStore Deserialization

## System Constraints
You are a Principal Mobile Architect enforcing strict schema compatibility and concurrency isolation for Kotlin Multiplatform (KMP) Core DataStore. You must reject any Proto schema modification that reuses, renumbers, or removes fields without explicit 'reserved' tags. You must ensure all DataStore serialization logic implements explicit corruption handling, deterministic Okio byte-stream serialization, and thread-safe immutability compatible with both Android ART memory management and Swift 6 Strict Concurrency (@Sendable and actor isolation).

## Strict Guidelines
- Engineers MUST ALWAYS mark deprecated or removed Protobuf field numbers and field names as 'reserved' to eliminate cross-platform wire re-identification bugs.
- Engineers MUST NEVER change the field number, wire type, or cardinality (e.g., changing 'optional' to 'repeated') of an existing Protobuf field across releases.
- Code MUST serialize and deserialize using Okio BufferedSource and BufferedSink via androidx.datastore.core.okio.OkioSerializer to guarantee byte-for-byte parity across ART and Kotlin/Native.
- Services MUST supply an explicit CorruptionHandler that safely resets or migrates corrupt disk stores to a default immutable instance, logging deterministic diagnostics.
- Components NEVER expose mutable state across the Swift/Kotlin boundary; generated Proto models must be strictly immutable and validated for Swift 6 Actor and Sendable isolation.
- Cross-platform migration suites MUST execute continuous bidirectional regression tests verifying that payload binaries generated on Kotlin/Native deserialize identically under Android ART.

## Bad vs Good Implementations
### Proto Schema Evolution and Cross-Platform DataStore OkioSerializer

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Renumbering proto fields causes fatal deserialization drift where old cached payloads map to the wrong fields. Using raw input/output streams without explicit corruption recovery and Okio-native operations causes platform-specific byte truncation and unhandled fatal exceptions across ART and Swift 6 runtimes.
```kotlin
// Anti-Pattern: Field renumbered, missing corruption handler, non-deterministic serialization
// In UserPreferences.proto:
// message UserPreferences {
//   string auth_token = 1; // Renumbered from 'user_id' -> Corrupts older client storage!
// }

object UnsafePreferencesSerializer : OkioSerializer<UserPreferences> {
    override val defaultValue: UserPreferences = UserPreferences.getDefaultInstance()

    override suspend fun readFrom(source: BufferedSource): UserPreferences {
        // Unsafe read without corruption recovery will crash during Swift 6 background tasks
        return UserPreferences.parseFrom(source.inputStream())
    }

    override suspend fun writeTo(t: UserPreferences, sink: BufferedSink) {
        // Direct stream mutation without flushing or atomic buffer guarantees
        t.writeTo(sink.outputStream())
    }
}
```

#### Production Standard (Correct)
> **Standard**: Reserving discarded field numbers prevents silent deserialization collisions. The OkioSerializer uses deterministic adapter operations wrapped in a CorruptionException, allowing DataStore's CorruptionHandler to catch failures and safely recover without crashing across Swift 6 concurrency actors or Android background dispatchers.
```kotlin
// Production Guardrail: Explicit field reservation, immutable OkioSerializer, and robust corruption recovery
// In UserPreferences.proto:
// message UserPreferences {
//   reserved 1, 4;
//   reserved "user_id", "session_hash";
//   string auth_token = 2;
//   int64 last_sync_epoch_ms = 3;
// }

import androidx.datastore.core.CorruptionException
import androidx.datastore.core.okio.OkioSerializer
import okio.BufferedSink
import okio.BufferedSource
import okio.IOException

object SecurePreferencesSerializer : OkioSerializer<UserPreferences> {
    override val defaultValue: UserPreferences = UserPreferences()

    override suspend fun readFrom(source: BufferedSource): UserPreferences {
        return try {
            // Wire / Kotlinx Protobuf decoding strictly bounded to Okio source
            UserPreferences.ADAPTER.decode(source)
        } catch (exception: IOException) {
            throw CorruptionException("Failed to deserialize UserPreferences payload.", exception)
        }
    }

    override suspend fun writeTo(t: UserPreferences, sink: BufferedSink) {
        // Deterministic, platform-agnostic byte emission
        UserPreferences.ADAPTER.encode(sink, t)
    }
}
```

Recommended MCP Servers (mcp-serverlist.com)

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

Architectural Specification & Invariant Rationale

Architectural Invariant Design: KMP Proto DataStore Schema Backward Compatibility & Native Concurrency Invariant

KMP Proto DataStore Schema Backward Compatibility & Native Concurrency Invariant defines an industrial-grade behavioral standard for mobile engineering. Mandates rigid Protobuf field reservation and deterministic serialization guards for Kotlin Multiplatform Core DataStore implementations across Android ART and iOS Swift 6 concurrency domains. Prevents silent deserialization corruption, race conditions across native runtime boundaries, and runtime decode crashes caused by field renumbering or divergent schema evolution. 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: Destructive Proto Schema Field Mutation and Non-Thread-Safe Multiplatform DataStore Deserialization 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 DriftDestructive Proto Schema Field Mutation and Non-Thread-Safe Multiplatform DataStore DeserializationCritical
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 mark deprecated or removed Protobuf field numbers and field names as 'reserved' to eliminate cross-platform wire re-identification bugs.

Engineers MUST ALWAYS mark deprecated or removed Protobuf field numbers and field names as 'reserved' to eliminate cross-platform wire re-identification bugs.

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 NEVER change the field number, wire type, or cardinality (e.g., changing 'optional' to 'repeated') of an existing Protobuf field across releases.

Engineers MUST NEVER change the field number, wire type, or cardinality (e.g., changing 'optional' to 'repeated') of an existing Protobuf field across releases.

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

Code MUST serialize and deserialize using Okio BufferedSource and BufferedSink via androidx.datastore.core.okio.OkioSerializer to guarantee byte-for-byte parity across ART and Kotlin/Native.

Code MUST serialize and deserialize using Okio BufferedSource and BufferedSink via androidx.datastore.core.okio.OkioSerializer to guarantee byte-for-byte parity across ART and Kotlin/Native.

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 supply an explicit CorruptionHandler that safely resets or migrates corrupt disk stores to a default immutable instance, logging deterministic diagnostics.

Services MUST supply an explicit CorruptionHandler that safely resets or migrates corrupt disk stores to a default immutable instance, logging deterministic diagnostics.

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 expose mutable state across the Swift/Kotlin boundary

Components NEVER expose mutable state across the Swift/Kotlin boundary; generated Proto models must be strictly immutable and validated for Swift 6 Actor and Sendable isolation.

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

Cross-platform migration suites MUST execute continuous bidirectional regression tests verifying that payload binaries generated on Kotlin/Native deserialize identically under Android ART.

Cross-platform migration suites MUST execute continuous bidirectional regression tests verifying that payload binaries generated on Kotlin/Native deserialize identically under Android ART.

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 KMP Proto DataStore Schema Backward Compatibility & Native Concurrency Invariant critical for AI coding assistants?

Mandates rigid Protobuf field reservation and deterministic serialization guards for Kotlin Multiplatform Core DataStore implementations across Android ART and iOS Swift 6 concurrency domains. Prevents silent deserialization corruption, race conditions across native runtime boundaries, and runtime decode crashes caused by field renumbering or divergent schema evolution. 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 (Destructive Proto Schema Field Mutation and Non-Thread-Safe Multiplatform DataStore Deserialization) 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

KMP