APPLE-002 — Apple Modernization Rules¶
Level 2 — Modernization Rules & Migration Governance
document:
id: APPLE-002
title: Apple Modernization Rules
version: "1.0"
track: platforms/apple
updated: 2026-07
next_review: 2027-WWDC
Separation of Duties¶
| Owns | Must NOT Own |
|---|---|
| Ratchet rules, migration records, acceptable technical debt definitions, modernization lifecycle, Net-Negative Ownership Delta formula | Apple capability catalog (APPLE-001). CI implementation details (APPLE-003). Verification receipts (APPLE-003/004). |
Dependencies: - Ratchet rules reference capability IDs from APPLE-001 §2. - Migration record IDs (OBS-001 etc.) are referenced by APPLE-003 §5 receipts and APPLE-004 §4 receipts.
1. Two Review Tracks¶
All Apple platform MRs are evaluated against two independent tracks.
Track 1 — Apple Modernization¶
Did this MR introduce deprecated or superseded Apple patterns?
Governed by ratchet rules in §2. CI enforcement via APPLE-003 §4.
Track 2 — Bluefly Architecture¶
Did this MR introduce unnecessary local ownership or architecture violations?
Governed by ratchet rules in §2. LOS impact evaluated in APPLE-004.
2. Ratchet Rules¶
Ratchet rules prevent regression. They apply to diff-added lines only — not the full codebase. Pre-existing violations are debt (§3), not gate failures.
Track 1 — Apple Modernization Ratchet¶
| Rule ID | Pattern | Action | Rationale |
|---|---|---|---|
| R-OBS | New ObservableObject, @StateObject, @ObservedObject, @Published |
FAIL | Superseded by @Observable (Swift 5.9+) |
| R-TEST | New import XCTest, XCTestCase, XCTAssert* |
FAIL | Superseded by Swift Testing (Swift 5.10+) |
| R-CONC | New @unchecked Sendable |
FAIL | Superseded by actor (Swift 5.7+) |
| R-DEP | New deprecated Apple API (from xcodebuild warnings) | FAIL | Use current API |
| R-NAV | New NavigationView |
FAIL | Superseded by NavigationSplitView / NavigationStack |
Track 2 — Bluefly Architecture Ratchet¶
| Rule ID | Pattern | Action | Rationale |
|---|---|---|---|
| R-SVC | New singleton manager (.shared pattern on new types) |
FAIL | Violates dependency clarity |
| R-ENV | New .environmentObject() injection |
FAIL | Superseded by @Environment with @Observable |
| R-DUP | New capability duplicated from APPLE-001 §5 | FAIL | Provider owns the capability |
| R-UNC | New unclassified type (no product/pack/adapter classification) | WARN | Every type needs a declared owner |
3. Migration Records (Pre-existing Debt)¶
These violations existed before the ratchet was introduced. They are tracked debts, not gate failures. MRs that introduce new instances of these patterns fail the gate (§2). MRs that reduce them improve LOS.
OBS-001 — State Observation: ObservableObject Classes¶
id: OBS-001
rule: R-OBS
description: Seven ViewModel classes use ObservableObject instead of @Observable
authority_capability: apple.observation # APPLE-001 §2
files:
- AgentViewModel.swift
- ChatViewModel.swift
- SessionViewModel.swift
- ProfileViewModel.swift
- CapabilityViewModel.swift
- SettingsViewModel.swift
- SidebarViewModel.swift
status: open
priority: high
admission_criteria: All seven classes migrated to @Observable; @StateObject replaced with @State
completion_criteria: Zero ObservableObject in codebase; Track 1 R-OBS passes on full scan
OBS-002 — State Observation: @StateObject/@ObservedObject Chain¶
id: OBS-002
rule: R-OBS
description: @StateObject and @ObservedObject usage throughout views, dependent on OBS-001
authority_capability: apple.observation
dependency: OBS-001
status: open
priority: high
admission_criteria: OBS-001 complete
completion_criteria: Zero @StateObject and @ObservedObject in codebase
CONC-001 — Concurrency: @unchecked Sendable Suppressions¶
id: CONC-001
rule: R-CONC
description: Two types suppress Sendable conformance instead of using actor isolation
authority_capability: apple.concurrency
files:
- CacheManager.swift
- MetricsStreamManager.swift
status: open
priority: medium
admission_criteria: Types analysed for shared mutable state
completion_criteria: Both types refactored to actor or provably Sendable without suppression
TEST-001 — Test Authorship: XCTest Throughout¶
id: TEST-001
rule: R-TEST
description: All tests use XCTestCase; no Swift Testing adoption
authority_capability: apple.testing
status: open
priority: medium
admission_criteria: New test target or test file created
completion_criteria: All new tests use Swift Testing; migration plan for existing tests documented
NAV-001 — Navigation: Redundant NavigationStack Nesting¶
id: NAV-001
rule: R-NAV
description: Nested NavigationStack instances creating redundant navigation hierarchy
authority_capability: apple.navigation
status: open
priority: low
admission_criteria: Navigation audit complete
completion_criteria: Single navigation root; no nested NavigationStack
4. Net-Negative Ownership Delta Formula¶
Compute for every MR. Included in APPLE-003 MR Verification Template.
Delta = (Deletions + Adoptions) − (New_Custom + New_Violations)
Where:
Deletions = lines of custom code removed (replaced by Apple API or deleted)
Adoptions = new Apple API calls replacing prior local code
New_Custom = new custom abstractions introduced
New_Violations = new ratchet rule violations (R-OBS, R-TEST, etc.)
Target: Delta ≥ 0 on every MR.
Delta > 0 means the MR reduced total ownership.
Delta = 0 means neutral (acceptable for functional MRs).
Delta < 0 means the MR increased ownership — requires justification.
5. Modernization Lifecycle¶
Admission¶
A migration record (§3) is created when: - A Track 1 ratchet violation is found in the existing codebase during an audit, or - A new Apple API supersedes a pattern currently in use.
The record is created in APPLE-002, not the MR. The MR gate references it by ID.
Active Migration¶
During migration, the record's status field is in_progress.
The MR introducing the migration work references the record ID in its description.
Completion¶
A migration is complete when:
1. The completion_criteria in the record are satisfied.
2. The APPLE-003 and APPLE-004 scores are recomputed.
3. The record status is updated to complete.
4. A migration receipt is appended to APPLE-004 §4.
Suspension¶
A migration may be suspended with documented justification if: - A platform requirement prevents migration (e.g., minimum deployment target). - The provider has deprecated the replacement API before the migration is complete. - Evidence is produced and recorded in the migration record.
Suspension does not close the record. It records the blocker.