# Swift rules

Apply these rules to every relevant file in this project.

- Do not assume this is safe: mechanically adding `[weak self]` to every escaping closure changes the lifetime policy to “silently skip the work when the object disappears.” If no caller retains the object elsewhere, a save, telemetry event, or state update may never happen.
  Source: [Automatic reference counting](https://codewiki.com/swift/arc/)
- Writing `guard let self` at the start of a long asynchronous closure upgrades the weak reference to a strong one for the entire remaining scope.
  Why: The code visibly uses `[weak self]`, yet the instance can remain alive until every `await` completes.
  Source: [Automatic reference counting](https://codewiki.com/swift/arc/)
- Replacing `weak` with `unowned` to avoid optional unwrapping turns recoverable target absence into a runtime error.
  Why: Delayed callbacks, cancellation, navigation, and test doubles can all violate a lifetime ordering inferred from the initial design.
  Source: [Automatic reference counting](https://codewiki.com/swift/arc/)
- A method reference can hide a strong capture.
  Why: Storing `self.handleUpdate` directly as a callback, subscription handler, or retry action contains no explicit closure syntax, but it can still make the storage owner strongly retain `self`.
  Source: [Automatic reference counting](https://codewiki.com/swift/arc/)
- Clearing a closure property or subscription token only in a success callback lets error, timeout, and cancellation paths keep the object graph alive.
  Why: A test suite that exercises only successful completion will not reveal this leak.
  Source: [Automatic reference counting](https://codewiki.com/swift/arc/)
- Do not assume this is safe: mechanically adding `[weak self]` to every escaping or asynchronous closure changes behavior to “silently skip when the object disappears.” A required save, callback, or state transition can vanish.
  Source: [Closures](https://codewiki.com/swift/closures/)
- Describing `[value]` as universally “capture by value” hides two facts: the entry is evaluated only at creation, and if the result is a class instance, the closure still strongly owns that same object.
  Source: [Closures](https://codewiki.com/swift/closures/)
- Adding `@escaping` to every closure parameter because it “might become async later” broadens the lifetime the API permits and forces callers to reason about the argument as a potentially stored callback.
  Source: [Closures](https://codewiki.com/swift/closures/)
- `@autoclosure` hides when an expression runs.
  Why: If an argument removes an array element, reads mutable state, or performs expensive work, an ordinary-looking function call can make reviewers assume the side effect has already happened.
  Source: [Closures](https://codewiki.com/swift/closures/)
- Generated code migrated from another language often claims that Swift closures in a `for`-`in` loop all see the final index and adds `[index]` unconditionally.
  Why: This confuses the per-iteration pattern binding with a shared mutable variable declared outside the loop.
  Source: [Closures](https://codewiki.com/swift/closures/)
- `var units = 0` doesn't make synthesized `init(from:)` retain `0` when JSON omits `units`.
  Why: The synthesized implementation still tries to decode that key and throws `keyNotFound`.
  Source: [Codable](https://codewiki.com/swift/codable/)
- `decodeIfPresent` returns `nil` both when a key is absent and when it is present with `null`.
  Why: That loses information when a patch endpoint uses those states to mean “leave unchanged” and “clear.”
  Source: [Codable](https://codewiki.com/swift/codable/)
- `.convertFromSnakeCase` turns `html_url` into `htmlUrl`; it doesn't infer that your property is spelled `htmlURL`.
  Why: Automatic strategies also aren't lossless inverses across every naming convention.
  Source: [Codable](https://codewiki.com/swift/codable/)
- The default date behavior of `JSONEncoder` and `JSONDecoder` isn't an ISO 8601 string and mustn't be assumed to be a Unix timestamp.
  Why: Generated clients often configure one direction and omit the other.
  Source: [Codable](https://codewiki.com/swift/codable/)
- `try?
  Why: decoder.decode(...)` compresses every failure into `nil`, so callers can't distinguish a missing key, a wrong type, a new enum value, or malformed JSON. It also discards the most useful `codingPath`.
  Source: [Codable](https://codewiki.com/swift/codable/)
- `Codable` checks whether a representation can construct the target type.
  Why: It doesn't check that a price is nonnegative, a URL has an allowed host, or a user may claim a role. Malicious input with the right primitive types can still decode.
  Source: [Codable](https://codewiki.com/swift/codable/)
- Adding `default` to shorten a `switch` sends every later case through old fallback behavior.
  Why: The code keeps compiling even when its business meaning is wrong.
  Source: [Enums and pattern matching](https://codewiki.com/swift/enums-pattern-matching/)
- `Enum(rawValue:)` proves only that a string or number maps to a case.
  Why: It doesn't prove that the case is allowed for this user, protocol version, or workflow stage.
  Source: [Enums and pattern matching](https://codewiki.com/swift/enums-pattern-matching/)
- A raw value is a fixed mapping for a case; it can't change per instance.
  Why: Modeling an order ID, error text, or progress as a raw value forces you to expand the case set or keep parallel storage.
  Source: [Enums and pattern matching](https://codewiki.com/swift/enums-pattern-matching/)
- A `switch` selects the first matching branch in source order.
  Why: If `.loading(let progress)` comes before the branch with `where progress < 0.5`, the latter is unreachable.
  Source: [Enums and pattern matching](https://codewiki.com/swift/enums-pattern-matching/)
- A chain of independent `if case` statements isn't exhaustive and can run multiple paths after conditions or state mutations overlap.
  Why: Adding a case doesn't force these checks to change.
  Source: [Enums and pattern matching](https://codewiki.com/swift/enums-pattern-matching/)
- Do not assume this is safe: two enum values can belong to the same case without supporting `==`.
  Why: Swift can synthesize `Equatable` only when the enum declares that conformance and every associated value can participate.
  Source: [Enums and pattern matching](https://codewiki.com/swift/enums-pattern-matching/)
- Wrapping decoding, disk writes, or permission checks in `try?` compresses every failure into the same `nil`.
  Why: The caller can't distinguish genuine absence from corrupt data, and monitoring loses the root cause.
  Source: [Error handling](https://codewiki.com/swift/error-handling/)
- `try!` isn't a compiler proof; it's a runtime assertion.
  Why: Test fixtures, bundled resources, and generated code can change with configuration or deployment, turning a supposedly infallible call into process termination.
  Source: [Error handling](https://codewiki.com/swift/error-handling/)
- A patternless `catch` before a specific branch shadows the later handling.
  Why: At an untyped `throws` boundary, handling only today's known errors also misses error types that a dependency adds later.
  Source: [Error handling](https://codewiki.com/swift/error-handling/)
- Replacing errors with `operationFailed` at every layer discards the underlying cause.
  Why: Conversely, making UI or domain code match filesystem and transport-library details leaks implementation across the abstraction boundary.
  Source: [Error handling](https://codewiki.com/swift/error-handling/)
- Do not assume this is safe: `throws` describes control flow, not transaction semantics.
  Why: Messages sent, external state changed, or partial data written before the throw aren't rolled back automatically, and `defer` only runs the cleanup you wrote.
  Source: [Error handling](https://codewiki.com/swift/error-handling/)
- Generated code sometimes puts an initialized property in an extension or uses a global dictionary keyed by object identity as an “attached field.” The first doesn't compile; the second creates lifetime, synchronization, and identity-reuse problems.
  Source: [Extensions](https://codewiki.com/swift/extensions/)
- A new method in a class extension can't be overridden by a subclass, and an extra protocol-extension member doesn't gain dynamic dispatch because a concrete type declares the same name.
  Why: The result can change with the variable's static type.
  Source: [Extensions](https://codewiki.com/swift/extensions/)
- Adding `Element: Equatable` to an entire generic type just to support one equality-based method also blocks unrelated features for every other element type.
  Source: [Extensions](https://codewiki.com/swift/extensions/)
- Broadly named members on common types such as `String` or `Array` can collide with another module or a future standard-library release.
  Why: A call that was unambiguous can become ambiguous when the import set changes.
  Source: [Extensions](https://codewiki.com/swift/extensions/)
- When the current module owns neither the type nor the protocol, adding a conformance occupies a globally unique type-protocol pair.
  Why: An upstream conformance added later can make different modules assume incompatible semantics for the same operation.
  Source: [Extensions](https://codewiki.com/swift/extensions/)
- Do not assume this is safe: moving an extension to another file can remove access to the original type's `private` members and can break synthesized conformances that depend on same-file rules.
  Why: Source placement affects visibility and what the compiler can generate.
  Source: [Extensions](https://codewiki.com/swift/extensions/)
- Generated code often writes `identity(42)`, borrowing explicit specialization syntax from other languages.
  Why: Swift rejects this call syntax even when `identity` declares `T`.
  Source: [Generics](https://codewiki.com/swift/generics/)
- A signature such as `[Any] -> Any` appears to accept more input, but it loses the relationship between the elements and result.
  Why: The function body is reduced to casts or runtime checks, and callers can't learn the result type from the signature.
  Source: [Generics](https://codewiki.com/swift/generics/)
- To make one `contains` method compile, a model may constrain an entire container with `Element: Equatable & Hashable & Codable`.
  Why: Callers that only need `count` must then satisfy abilities irrelevant to their operation.
  Source: [Generics](https://codewiki.com/swift/generics/)
- `[T]` has one `T` in any concrete use.
  Why: A generic array can't automatically hold both `Circle` and `Rectangle` merely because both conform to `Shape`.
  Source: [Generics](https://codewiki.com/swift/generics/)
- `some Protocol` preserves one hidden concrete type identity, while `any Protocol` stores a conforming value whose concrete type may vary at runtime.
  Why: A mechanical replacement can break same-type relationships or make members that depend on associated types unavailable.
  Source: [Generics](https://codewiki.com/swift/generics/)
- Generated code often adds `!` when the compiler requires it to handle a `String?`.
  Why: That only converts a compile-time prompt into a runtime trap; asynchronous responses, empty collections, and test fixtures can all break the original non-`nil` assumption.
  Source: [Optionals](https://codewiki.com/swift/optionals/)
- `Int(text) ??
  Why: 0` turns a real zero, missing input, and malformed input into the same `0`. If zero has business meaning, later code can't recover the original state and may persist bad data.
  Source: [Optionals](https://codewiki.com/swift/optionals/)
- When `account?.owner?.email` returns `nil`, it doesn't record which link was absent.
  Why: Using that result directly for error messages or analytics mixes states that may have different remedies.
  Source: [Optionals](https://codewiki.com/swift/optionals/)
- `[Order]?` means the entire collection may be absent; `[Order?]` means the collection exists but individual positions may be missing.
  Why: Immediately converting either form to `[Order]` with `compactMap` deletes information from a different source.
  Source: [Optionals](https://codewiki.com/swift/optionals/)
- Reading `[Key: Value?]` by subscript produces `Value??`.
  Why: Consecutive bindings or `flatMap { $0 }` are convenient, but they merge "key absent" and "key present with no value."
  Source: [Optionals](https://codewiki.com/swift/optionals/)
- A wrapper named `Validated` or `Clamped` can silently replace invalid input with a default or previous value.
  Why: The caller sees an ordinary assignment and may assume the new value was stored.
  Source: [Property wrappers](https://codewiki.com/swift/property-wrappers/)
- Locking the getter and setter separately doesn't make `counter.count += 1` atomic.
  Why: That expression reads under one lock and writes under another, so a competing execution can interleave between them.
  Source: [Property wrappers](https://codewiki.com/swift/property-wrappers/)
- A generic `UserDefaults` wrapper often uses `as?
  Why: Value ?? defaultValue`, collapsing absence, an old schema, a wrong type, and corrupt data into the same default. It may also treat every `Codable` value as though `UserDefaults` natively supported it.
  Source: [Property wrappers](https://codewiki.com/swift/property-wrappers/)
- Do not treat every `$property` as a `Binding` or wrapper instance produces type errors.
  Why: The presence, type, and mutability of a projection come entirely from that wrapper's `projectedValue`, and composition exposes only the outermost projection.
  Source: [Property wrappers](https://codewiki.com/swift/property-wrappers/)
- Do not assume this is safe: synthesized `Codable` conformance processes backing storage instead of bypassing the wrapper to process the domain value.
  Why: Even when the wrapper has a default, a wholly missing key can fail before the wrapper's `init(from:)` gets control.
  Source: [Property wrappers](https://codewiki.com/swift/property-wrappers/)
- `Any` or `[any P]` can hold different runtime types, but it doesn't preserve proof that an input and output have the same type.
  Why: Callers must then cast, moving errors from compile time to runtime.
  Source: [Protocol constraints and existentials](https://codewiki.com/swift/protocols-generics/)
- Only one sorting method needs `Comparable`, but generated code may declare the entire container as `Box`.
  Why: Every unrelated operation then rejects other element types.
  Source: [Protocol constraints and existentials](https://codewiki.com/swift/protocols-generics/)
- `some P` hides one underlying type; it doesn't select a different conformer on each execution.
  Why: If ordinary `if` branches return unrelated types, the compiler can't determine one underlying type for the declaration.
  Source: [Protocol constraints and existentials](https://codewiki.com/swift/protocols-generics/)
- A member declared only in a protocol extension is selected statically.
  Why: A same-named concrete member doesn't automatically become its dynamic replacement at generic or existential boundaries.
  Source: [Protocol constraints and existentials](https://codewiki.com/swift/protocols-generics/)
- Generated `AnyRepository` wrappers often store values as `Any` and recover them with `as!`.
  Why: A registration mistake then traps far from its cause, and the associated-type relationship was never truly preserved.
  Source: [Protocol constraints and existentials](https://codewiki.com/swift/protocols-generics/)
- A protocol extension adds `render()`, and a concrete type declares a method with the same name, which looks like an override.
  Why: Once the value is stored as `any Protocol`, the call can return to the extension implementation.
  Source: [Protocols](https://codewiki.com/swift/protocols/)
- Do not assume this is safe: generated code often shortens `` to `any P` while losing facts such as two arguments sharing a type, a result depending on its input, or an associated type being fixed.
  Source: [Protocols](https://codewiki.com/swift/protocols/)
- `{ get }` promises only that callers can read; it doesn't require an immutable implementation.
  Why: `{ get set }` promises writes through the protocol interface. Changing the former to the latter excludes otherwise valid read-only computed properties.
  Source: [Protocols](https://codewiki.com/swift/protocols/)
- `any P` can hold a value that conforms to `P`, but that doesn't mean the box itself conforms to `P` in every generic context.
  Why: The difference becomes visible around `Self`, associated-type inputs, and nested collections.
  Source: [Protocols](https://codewiki.com/swift/protocols/)
- A default lets a new conformance compile, but it can silently apply generic behavior where a domain type should explicitly decide authorization, retries, or persistence.
  Source: [Protocols](https://codewiki.com/swift/protocols/)
- Do not treat “a structure is a value type” as “the whole object graph is deep-copied” leaves nested class instances shared by accident.
  Why: Fix: inspect every stored property's semantics; prefer values inside a snapshot boundary, provide an explicit copy when a class instance must be independent, and test interleaved mutations of both copies.
  Source: [Structures and classes](https://codewiki.com/swift/structs-classes/)
- Do not assume this is safe: `let service = Service()` fixes which instance `service` references; it does not make the instance's `var` properties immutable.
  Why: Fix: maintain class invariants with access control, immutable properties, and narrow methods; return a structure value instead of exposing a mutable instance when callers need a snapshot.
  Source: [Structures and classes](https://codewiki.com/swift/structs-classes/)
- Do not depend on a synthesized memberwise initializer as public API; doing so can break callers when a stored property or handwritten initializer is added, and its access level can be lower than the type's.
  Why: Fix: explicitly declare construction paths promised to other modules, and treat memberwise synthesis as an implementation convenience rather than a stable interface.
  Source: [Structures and classes](https://codewiki.com/swift/structs-classes/)
- Turning a structure into a class merely because one method mutates state silently introduces aliasing, a shared lifetime, and possible concurrent access.
  Why: Fix: first try a `mutating` method, return a new value, or keep the structure under one owner; use a class only when shared identity is itself a requirement.
  Source: [Structures and classes](https://codewiki.com/swift/structs-classes/)
- Predicting performance from “structures are on the stack and classes are on the heap” is unreliable; escape analysis, generic specialization, boxing, and internal buffers all affect actual storage and copy costs.
  Why: Fix: choose by semantics, then profile an optimized build under a representative workload. Without measurements, do not claim that a structure or class is necessarily faster.
  Source: [Structures and classes](https://codewiki.com/swift/structs-classes/)
- Do not assume this is safe: using `===` for business-content equality, or assuming two class instances with equal fields have the same identity, confuses identity with equality.
  Why: Fix: use `===` to ask whether class references point to one instance; define `Equatable` and use `==` for content equality, and state which relation an API requires.
  Source: [Structures and classes](https://codewiki.com/swift/structs-classes/)
- Do not treat inferred declarations as dynamically typed leads to assignments that cannot compile.
  Source: [Swift fundamentals](https://codewiki.com/swift/fundamentals/)
- Do not assume this is safe: a numeric conversion is not permission to ignore range, precision, or units.
  Source: [Swift fundamentals](https://codewiki.com/swift/fundamentals/)
- Do not assume this is safe: `array[index]` does not return an optional.
  Source: [Swift fundamentals](https://codewiki.com/swift/fundamentals/)
- Do not assume this is safe: set and dictionary iteration order is not a presentation contract.
  Source: [Swift fundamentals](https://codewiki.com/swift/fundamentals/)
- Do not assume this is safe: a Swift `String` is not an array of UTF-16 code units, bytes, or integer-indexed characters.
  Source: [Swift fundamentals](https://codewiki.com/swift/fundamentals/)
