Merge contract
15-question review gate
ShippedReview gateThe fleet questionnaire. Six questions are merge blockers. The rest need an explicit answer or N/A. Use it while you work, then again on the PR.
Merge blockers are Q1, Q2, Q6, Q8, Q9, Q14. Pre-commit questions can become ast-grep/CI. Review questions need judgment — unchecked means an explicit rationale or N/A, not silence.
Type & expression
- Q1
Enums over magic strings
merge blockerpre-commitEvery string that is really a finite set (states, labels, error kinds, allowlists, lanes, list markers) is an enum with exhaustive switches; CaseIterable where tests should iterate.
- Q2
Codable on the wire
merge blockerpre-commitNo hand-built JSON string literals in production code. Error frames, DTOs, and happy-path fixtures encode from types. Byte-equality where wire shape matters. macOS 26 JSONEncoder randomizes key order per-process — stable bytes need a canonical writer (Exhibit 13).
- Q3
Smallest clear expression
reviewFunction vs computed property — honest about cost. Prefer switch over chained ifs; guard let for early exit, if let for local branch, for case let for filtered pattern-matching.
- Q4
Protocol vs enum
reviewProtocols only where implementations genuinely vary. Finite variation = enum, not a protocol hierarchy.
- Q5
Functional Swift where it fits
reviewmap/compactMap/flatMap/reduce when the source is a collection and the transform is pure. Keep streaming loops when collecting would allocate, delay results, or hide side effects.
Concurrency & streams
- Q6
Actors / Sendable
merge blockerpre-commitShared mutable state is actor-isolated or value-typed Sendable. Every @unchecked Sendable carries a written justification. Cross-boundary values conform to Sendable.
- Q7
Smallest honest lifetime model
reviewValue, one-shot async function, or AsyncSequence? Choose the smallest model that represents the real lifetime. Combine only at real publisher boundaries.
Observability & security
- Q8
Emoji telemetry at every decision point
merge blockerpre-commitEach meaningful branch emits a typed event with a glyph through one enum surface. A new decision point without an event fails the gate.
- Q9
Secrets & data posture
merge blockerpre-commitNo ambient environment inheritance. Auth before privileged side effects. No PII in logs. Brokered secrets, never embedded. App Control /state never dumps Keychain.
UI
- Q10
Xcode Previews
reviewEvery new UI state covered: loading / empty / error / long content / Dynamic Type / dark mode. Preview-parity suites where the repo has them.
- Q11
Snapshot tests
reviewLayout/rendering regressions that matter have snapshots — baselines are CI-recorded, never studio-recorded. A green suite against a void baseline proves nothing (Exhibit 7).
- Q12
Interaction feedback
reviewIntentional haptics for meaningful taps; a11y labels; identifiers for control vs labels for humans. No fake live states.
Quality
- Q13
Performance
reviewHot path allocation-conscious. No sync work on the main/timeline thread. No accidental O(n²).
- Q14
Exhaustive proof
merge blockerpre-commitCaseIterable drives tests. Behavioral changes carry a rendered sequence/flow diagram; UI changes carry a snapshot gallery. E2E paths proven by running them — receipts posted, not vibes.
- Q15
Better shape?
reviewIs there a simpler API — fewer types, less indirection — that still keeps Q1–Q14? If not, say why in the PR.