"443 tests passed four separate times while the iOS code did not compile at all."
Where Shared Code Lives
Two kinds of sharing show up in a family of Apple apps. Within one product, a Mac app and its iPhone app share a model, a wire protocol and a client core. Across products, a dozen apps share the same hardened HTTP transport, document store, outbox and watch link. The family answers both with Swift packages rather than copies. A Mac terminal-and-agent client, for example, keeps a protocol module with no platform guards at all and a client-core module where only the transport differs by platform — a child process on the Mac, a WebSocket to the home gateway on the phone. When the phone client arrived, it linked the same two modules instead of re-implementing them.
The shared family kit is one package with several products (core, web host, speech, media, Mac chrome, watch link, push, server, and server test helpers), consumed by path. A handful of tiny single-file helpers are still distributed as vendored copies, kept byte-identical by a sync script and a drift test in every consumer; the rule for which mechanism applies is simply whether the file depends on another kit file. Kit files are edited in the kit, never in a consumer.
Fences Decide What Compiles
Platform-specific code sits behind compile-time conditions: #if os(macOS), #if canImport(UIKit) && !os(watchOS), #if canImport(WatchConnectivity). A fence does not just skip code at run time — code outside the current platform is not compiled at all. That is where the family's kit fooled itself: swift test on a Mac builds the package for macOS only. On one day it ran 443 tests green four times while the iOS and watchOS code behind the fences contained a wrist enum that did not compile on iOS, a delegate conformance Swift 6 refused, completion handlers flagged as data races, and an API that does not exist on watchOS — the last of them landed thirty minutes after a commit, with a green suite.
The check is to build each product for each platform it claims, with xcodebuild pointed at the package directory and a generic destination. A shared -derivedDataPath keeps the matrix incremental: the family's matrix builds nine products for iOS and eight of them for watchOS, 17 builds in all, in about 49 seconds cold and 24 warm, and the kit's own test runner calls it.
Apps First, Kit Monitored
A shared layer that apps must wait for is a shared layer that ships nothing. The family's ruling is that an app implements a missing capability locally at once — labelled app-owned, pending migration, never presented as a kit copy — while watching the kit, and adopts the kit version once it can really replace the local one, deleting the duplicate and verifying behaviour did not change. Temporary duplication is allowed; unlabelled duplication is not, because no drift check can see a copy it does not know about.