diff --git a/CHANGELOG.md b/CHANGELOG.md
index 55bea7927..a03713b8a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+### Fixed
+
+- iCloud Sync between the iPhone and Mac apps: the iOS app now uses the Production CloudKit environment, so a development build no longer syncs into a separate database the Mac never reads.
+
## [0.50.0] - 2026-06-09
### Added
diff --git a/TableProMobile/TableProMobile/TableProMobileRelease.entitlements b/TableProMobile/TableProMobile/TableProMobileRelease.entitlements
index f8880a803..3ae2bfe54 100644
--- a/TableProMobile/TableProMobile/TableProMobileRelease.entitlements
+++ b/TableProMobile/TableProMobile/TableProMobileRelease.entitlements
@@ -10,6 +10,8 @@
CloudKit
+ com.apple.developer.icloud-container-environment
+ Production
com.apple.security.application-groups
group.com.TablePro.TableProMobile
diff --git a/TableProTests/Core/Sync/EntitlementsEnvironmentParityTests.swift b/TableProTests/Core/Sync/EntitlementsEnvironmentParityTests.swift
new file mode 100644
index 000000000..3fee5a9d9
--- /dev/null
+++ b/TableProTests/Core/Sync/EntitlementsEnvironmentParityTests.swift
@@ -0,0 +1,53 @@
+//
+// EntitlementsEnvironmentParityTests.swift
+// TableProTests
+//
+// Guards the CloudKit environment pin. The Mac and iOS apps must both target
+// the Production environment, or a development iOS build talks to the
+// Development database while the Mac talks to Production and sync silently
+// moves nothing across devices.
+//
+
+import Foundation
+import Testing
+
+@Suite("CloudKit environment entitlement parity")
+struct EntitlementsEnvironmentParityTests {
+ private static let environmentKey = "com.apple.developer.icloud-container-environment"
+ private static let macEntitlements = "TablePro/TablePro.entitlements"
+ private static let iosEntitlements = "TableProMobile/TableProMobile/TableProMobileRelease.entitlements"
+
+ @Test("Mac app pins the Production CloudKit environment")
+ func macTargetsProduction() throws {
+ try #expect(environment(in: Self.macEntitlements) == "Production")
+ }
+
+ @Test("iOS app pins the Production CloudKit environment")
+ func iosTargetsProduction() throws {
+ try #expect(environment(in: Self.iosEntitlements) == "Production")
+ }
+
+ private func environment(in relativePath: String) throws -> String? {
+ let url = try repoRoot().appendingPathComponent(relativePath)
+ let data = try Data(contentsOf: url)
+ let plist = try PropertyListSerialization.propertyList(from: data, format: nil)
+ let entitlements = try #require(plist as? [String: Any], "Entitlements at \(relativePath) is not a dictionary")
+ return entitlements[Self.environmentKey] as? String
+ }
+
+ private func repoRoot(file: StaticString = #filePath) throws -> URL {
+ var directory = URL(fileURLWithPath: "\(file)").deletingLastPathComponent()
+ while directory.path != "/" {
+ let marker = directory.appendingPathComponent("TablePro.xcodeproj")
+ if FileManager.default.fileExists(atPath: marker.path) {
+ return directory
+ }
+ directory = directory.deletingLastPathComponent()
+ }
+ throw EntitlementsParityError.repoRootNotFound
+ }
+
+ private enum EntitlementsParityError: Error {
+ case repoRootNotFound
+ }
+}