@leejungkiin/awkit 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/VERSION +1 -1
- package/core/GEMINI.md.bak +168 -181
- package/package.json +2 -2
- package/schemas/brain-snapshot.json +167 -0
- package/skills/CATALOG.md +70 -0
- package/skills/beads-manager/SKILL.md +20 -1
- package/skills/memory-sync/SKILL.md +20 -2
- package/skills/nm-memory-audit/SKILL.md +157 -0
- package/skills/nm-memory-evolution/SKILL.md +202 -0
- package/skills/nm-memory-intake/SKILL.md +135 -0
- package/skills/nm-memory-sync/SKILL.md +184 -0
- package/skills/orchestrator/SKILL.md +41 -50
- package/skills/schemas/brain-snapshot.json +167 -0
- package/skills/skills/nm-memory-audit/SKILL.md +157 -0
- package/skills/skills/nm-memory-evolution/SKILL.md +202 -0
- package/skills/skills/nm-memory-intake/SKILL.md +135 -0
- package/skills/skills/nm-memory-sync/SKILL.md +184 -0
- package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/smali-to-swift/phase-0-discovery.md +137 -0
- package/skills/smali-to-swift/phase-1-architecture.md +168 -0
- package/skills/smali-to-swift/phase-2-blueprint-ui.md +348 -0
- package/skills/smali-to-swift/phase-2-blueprint.md +173 -0
- package/skills/smali-to-swift/phase-3-build.md +257 -0
- package/skills/smali-to-swift/phase-3-logic-build.md +312 -0
- package/skills/smali-to-swift/templates/app-map.md +82 -0
- package/skills/smali-to-swift/templates/architecture.md +97 -0
- package/skills/smali-to-swift/templates/blueprint.md +82 -0
- package/skills/workflows/nm-import.md +73 -0
- package/skills/workflows/nm-recall.md +67 -0
- package/skills/workflows/nm-snapshot.md +69 -0
- package/workflows/_uncategorized/nm-import.md +73 -0
- package/workflows/_uncategorized/nm-recall.md +67 -0
- package/workflows/_uncategorized/nm-snapshot.md +69 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/workflows/mobile/reverse-android-build.md +119 -79
- package/workflows/mobile/reverse-android-design.md +10 -7
- package/workflows/mobile/reverse-android.md +52 -46
- package/workflows/mobile/reverse-ios-build.md +161 -50
- package/workflows/mobile/reverse-ios-design.md +10 -1
- package/workflows/mobile/reverse-ios.md +49 -37
- package/skills/adaptive-language/SKILL.md +0 -189
- package/skills/ambient-brain/SKILL.md +0 -314
- package/skills/ambient-brain/brain-router.md +0 -185
- package/skills/ambient-brain/brain-templates.md +0 -201
- package/skills/context-help/SKILL.md +0 -180
- package/skills/error-translator/SKILL.md +0 -153
- package/skills/session-restore/SKILL.md +0 -240
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# 📐 Phase 2: Blueprint (Block View — per feature) — iOS
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 2 — Feature Detail
|
|
4
|
+
> **Goal:** Design contracts and state for ONE specific feature.
|
|
5
|
+
> **Input:** Architecture Blueprint (Phase 1) + user's chosen feature.
|
|
6
|
+
> **Output:** Feature Blueprint with code signatures. **NO implementation bodies yet.**
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ⛔ OUTPUT RULE
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
✅ ALLOWED: Protocol signatures, struct definitions, enum cases
|
|
14
|
+
✅ ALLOWED: Endpoint definitions (path + method, no body)
|
|
15
|
+
✅ ALLOWED: State design (@Observable properties, no logic)
|
|
16
|
+
❌ BLOCKED: Function body implementations
|
|
17
|
+
❌ BLOCKED: Full ViewModel logic, full View implementations
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 📋 Sub-steps (per feature)
|
|
23
|
+
|
|
24
|
+
### 2.1: Deep Header/Disassembly Reading
|
|
25
|
+
|
|
26
|
+
Read class-dump headers + Hopper pseudo-code for the chosen feature.
|
|
27
|
+
|
|
28
|
+
**What to extract:**
|
|
29
|
+
- Class hierarchy (@interface ... : NSObject)
|
|
30
|
+
- Properties → model fields
|
|
31
|
+
- Method signatures → API contracts
|
|
32
|
+
- String constants → URLs, keys
|
|
33
|
+
- Delegate/datasource patterns → business rules
|
|
34
|
+
|
|
35
|
+
**ObjC Header Reading Quick Ref:**
|
|
36
|
+
```objc
|
|
37
|
+
@property (nonatomic, copy) NSString *name; // → let name: String
|
|
38
|
+
@property (nonatomic, strong) NSArray *items; // → let items: [Any]
|
|
39
|
+
@property (nonatomic, assign) BOOL isActive; // → let isActive: Bool
|
|
40
|
+
@property (nonatomic, assign) NSInteger count; // → let count: Int
|
|
41
|
+
@property (nullable) NSString *bio; // → let bio: String?
|
|
42
|
+
|
|
43
|
+
- (void)fetchWithCompletion:(void(^)(id, NSError*))completion;
|
|
44
|
+
// → func fetch() async throws -> T
|
|
45
|
+
|
|
46
|
+
+ (instancetype)sharedInstance;
|
|
47
|
+
// → static let shared = ClassName()
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2.2: Domain Model Contracts
|
|
51
|
+
|
|
52
|
+
```swift
|
|
53
|
+
struct User: Codable, Identifiable, Sendable {
|
|
54
|
+
let id: String
|
|
55
|
+
let fullName: String
|
|
56
|
+
let email: String
|
|
57
|
+
let avatarUrl: String?
|
|
58
|
+
let isVerified: Bool
|
|
59
|
+
|
|
60
|
+
enum CodingKeys: String, CodingKey {
|
|
61
|
+
case id = "user_id"
|
|
62
|
+
case fullName = "full_name"
|
|
63
|
+
case email
|
|
64
|
+
case avatarUrl = "avatar_url"
|
|
65
|
+
case isVerified = "is_verified"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2.3: Repository Contract
|
|
71
|
+
|
|
72
|
+
```swift
|
|
73
|
+
protocol AuthRepository: Sendable {
|
|
74
|
+
func login(email: String, password: String) async throws -> User
|
|
75
|
+
func register(name: String, email: String, password: String) async throws -> User
|
|
76
|
+
func logout() async
|
|
77
|
+
var isLoggedIn: AsyncStream<Bool> { get }
|
|
78
|
+
var currentUser: AsyncStream<User?> { get }
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2.4: API Contract
|
|
83
|
+
|
|
84
|
+
```swift
|
|
85
|
+
enum AuthEndpoint: Endpoint {
|
|
86
|
+
case login(email: String, password: String)
|
|
87
|
+
case register(name: String, email: String, password: String)
|
|
88
|
+
case currentUser
|
|
89
|
+
|
|
90
|
+
var path: String { /* ... */ }
|
|
91
|
+
var method: HTTPMethod { /* ... */ }
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 2.5: UseCase Signatures
|
|
96
|
+
|
|
97
|
+
```swift
|
|
98
|
+
struct LoginUseCase: Sendable {
|
|
99
|
+
let authRepository: AuthRepository
|
|
100
|
+
func execute(email: String, password: String) async throws -> User
|
|
101
|
+
// Implementation: TODO
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### 2.6: UI State Design
|
|
106
|
+
|
|
107
|
+
```swift
|
|
108
|
+
// ViewModel properties (will be @Observable)
|
|
109
|
+
// - email: String
|
|
110
|
+
// - password: String
|
|
111
|
+
// - isLoading: Bool
|
|
112
|
+
// - showError: Bool
|
|
113
|
+
// - errorMessage: String
|
|
114
|
+
// - isPasswordVisible: Bool
|
|
115
|
+
|
|
116
|
+
// Actions the view can trigger:
|
|
117
|
+
// - updateEmail(String)
|
|
118
|
+
// - updatePassword(String)
|
|
119
|
+
// - togglePasswordVisibility()
|
|
120
|
+
// - login()
|
|
121
|
+
|
|
122
|
+
// Navigation events:
|
|
123
|
+
// - navigateToHome(User)
|
|
124
|
+
// - showSnackbar(String)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 2.7: UI Wireframe
|
|
128
|
+
|
|
129
|
+
```markdown
|
|
130
|
+
### LoginScreen Wireframe
|
|
131
|
+
┌──────────────────────┐
|
|
132
|
+
│ [App Logo] │
|
|
133
|
+
│ │
|
|
134
|
+
│ ┌──────────────────┐ │
|
|
135
|
+
│ │ Email TextField │ │
|
|
136
|
+
│ └──────────────────┘ │
|
|
137
|
+
│ ┌──────────────────┐ │
|
|
138
|
+
│ │ Password Field 👁│ │
|
|
139
|
+
│ └──────────────────┘ │
|
|
140
|
+
│ │
|
|
141
|
+
│ [═══ Login Button ══]│
|
|
142
|
+
│ │
|
|
143
|
+
│ Forgot Password? │
|
|
144
|
+
│ Register │
|
|
145
|
+
└──────────────────────┘
|
|
146
|
+
|
|
147
|
+
Behaviors:
|
|
148
|
+
- Email: .textContentType(.emailAddress), .keyboardType(.emailAddress)
|
|
149
|
+
- Password: toggle visibility, .textContentType(.password)
|
|
150
|
+
- Button: .disabled when loading, overlay ProgressView
|
|
151
|
+
- Error: .alert modifier
|
|
152
|
+
- Success: NavigationStack push to Home
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 📊 Output: Feature Blueprint
|
|
158
|
+
|
|
159
|
+
Use template from `templates/blueprint.md`.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## ✅ Gate
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
"📐 Blueprint cho [Feature] xong. Anh xem contracts ổn không?"
|
|
167
|
+
→ OK → Phase 3 (Implementation)
|
|
168
|
+
→ Adjust → Update blueprint
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
*Phase 2: Blueprint — Contracts before code*
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# 🔨 Phase 3: Implementation (Ground View — per feature) — iOS
|
|
2
|
+
|
|
3
|
+
> **Zoom Level:** 3 — Code Implementation
|
|
4
|
+
> **Goal:** Write actual, production-quality Swift code for ONE feature.
|
|
5
|
+
> **Input:** Approved Blueprint from Phase 2.
|
|
6
|
+
> **Output:** Complete implementation files.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## ✅ PREREQUISITES
|
|
11
|
+
|
|
12
|
+
Before writing ANY code, confirm:
|
|
13
|
+
- [ ] Phase 0 App Map approved
|
|
14
|
+
- [ ] Phase 1 Architecture Blueprint approved
|
|
15
|
+
- [ ] Phase 2 Feature Blueprint approved for THIS feature
|
|
16
|
+
- [ ] All contracts (protocols, models, state) defined in Blueprint
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 📋 Implementation Order (per feature)
|
|
21
|
+
|
|
22
|
+
### 3.1: Domain Layer
|
|
23
|
+
|
|
24
|
+
1. **Models** — Codable structs from Blueprint 2.2
|
|
25
|
+
2. **Repository protocols** — from Blueprint 2.3
|
|
26
|
+
3. **UseCases** — implement with repository calls
|
|
27
|
+
|
|
28
|
+
```swift
|
|
29
|
+
struct LoginUseCase: Sendable {
|
|
30
|
+
let authRepository: AuthRepository
|
|
31
|
+
|
|
32
|
+
func execute(email: String, password: String) async throws -> User {
|
|
33
|
+
try await authRepository.login(email: email, password: password)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 3.2: Data Layer
|
|
39
|
+
|
|
40
|
+
1. **DTOs** — Codable structs matching API JSON
|
|
41
|
+
2. **Endpoint definitions** — enum with path/method
|
|
42
|
+
3. **APIClient** — URLSession async/await wrapper
|
|
43
|
+
4. **SwiftData models** (if applicable)
|
|
44
|
+
5. **Repository implementation** — offline-first
|
|
45
|
+
|
|
46
|
+
```swift
|
|
47
|
+
final class AuthRepositoryImpl: AuthRepository, Sendable {
|
|
48
|
+
private let apiClient: APIClient
|
|
49
|
+
private let tokenStore: TokenStore
|
|
50
|
+
|
|
51
|
+
func login(email: String, password: String) async throws -> User {
|
|
52
|
+
let response: LoginResponse = try await apiClient.request(
|
|
53
|
+
.login(email: email, password: password)
|
|
54
|
+
)
|
|
55
|
+
await tokenStore.save(response.accessToken)
|
|
56
|
+
return response.user.toDomain()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
var isLoggedIn: AsyncStream<Bool> {
|
|
60
|
+
tokenStore.tokenStream.map { !$0.isEmpty }.eraseToStream()
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 3.3: DI Container
|
|
66
|
+
|
|
67
|
+
```swift
|
|
68
|
+
@MainActor
|
|
69
|
+
final class AppContainer: Observable {
|
|
70
|
+
private let apiClient: APIClient
|
|
71
|
+
|
|
72
|
+
lazy var authRepository: AuthRepository = AuthRepositoryImpl(
|
|
73
|
+
apiClient: apiClient,
|
|
74
|
+
tokenStore: tokenStore
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
lazy var loginUseCase = LoginUseCase(authRepository: authRepository)
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 3.4: ViewModel
|
|
82
|
+
|
|
83
|
+
@Observable with properties from Blueprint:
|
|
84
|
+
|
|
85
|
+
```swift
|
|
86
|
+
@Observable
|
|
87
|
+
final class LoginViewModel {
|
|
88
|
+
var email = ""
|
|
89
|
+
var password = ""
|
|
90
|
+
var isLoading = false
|
|
91
|
+
var showError = false
|
|
92
|
+
var errorMessage = ""
|
|
93
|
+
var isPasswordVisible = false
|
|
94
|
+
|
|
95
|
+
private let loginUseCase: LoginUseCase
|
|
96
|
+
|
|
97
|
+
init(loginUseCase: LoginUseCase) {
|
|
98
|
+
self.loginUseCase = loginUseCase
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
func login() async {
|
|
102
|
+
isLoading = true
|
|
103
|
+
defer { isLoading = false }
|
|
104
|
+
|
|
105
|
+
do {
|
|
106
|
+
let user = try await loginUseCase.execute(email: email, password: password)
|
|
107
|
+
// Navigation handled by parent
|
|
108
|
+
} catch {
|
|
109
|
+
errorMessage = error.localizedDescription
|
|
110
|
+
showError = true
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 3.5: SwiftUI Screen
|
|
117
|
+
|
|
118
|
+
```swift
|
|
119
|
+
struct LoginScreen: View {
|
|
120
|
+
@State private var viewModel: LoginViewModel
|
|
121
|
+
var onLoginSuccess: (User) -> Void
|
|
122
|
+
|
|
123
|
+
init(loginUseCase: LoginUseCase, onLoginSuccess: @escaping (User) -> Void) {
|
|
124
|
+
_viewModel = State(initialValue: LoginViewModel(loginUseCase: loginUseCase))
|
|
125
|
+
self.onLoginSuccess = onLoginSuccess
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var body: some View {
|
|
129
|
+
ScrollView {
|
|
130
|
+
VStack(spacing: 24) {
|
|
131
|
+
// Logo
|
|
132
|
+
// Email TextField
|
|
133
|
+
TextField("Email", text: $viewModel.email)
|
|
134
|
+
.textContentType(.emailAddress)
|
|
135
|
+
.keyboardType(.emailAddress)
|
|
136
|
+
.textFieldStyle(.roundedBorder)
|
|
137
|
+
|
|
138
|
+
// Password SecureField
|
|
139
|
+
// Login Button
|
|
140
|
+
Button("Login") {
|
|
141
|
+
Task { await viewModel.login() }
|
|
142
|
+
}
|
|
143
|
+
.buttonStyle(.borderedProminent)
|
|
144
|
+
.disabled(viewModel.isLoading)
|
|
145
|
+
}
|
|
146
|
+
.padding(24)
|
|
147
|
+
}
|
|
148
|
+
.overlay { if viewModel.isLoading { ProgressView() } }
|
|
149
|
+
.alert("Error", isPresented: $viewModel.showError) {
|
|
150
|
+
Button("OK") {}
|
|
151
|
+
} message: {
|
|
152
|
+
Text(viewModel.errorMessage)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### 3.6: Resource Extraction (On-Demand)
|
|
159
|
+
|
|
160
|
+
**ONLY** extract resources used by this screen:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Images from Assets.car (use assetutil)
|
|
164
|
+
# Strings from Localizable.strings for this VC
|
|
165
|
+
# Colors referenced in storyboard for this screen
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 🔒 CRYPTO UTILS (Special Handling)
|
|
171
|
+
|
|
172
|
+
If the feature involves encryption/hashing:
|
|
173
|
+
|
|
174
|
+
```swift
|
|
175
|
+
import CryptoKit
|
|
176
|
+
import CommonCrypto
|
|
177
|
+
|
|
178
|
+
enum CryptoUtils {
|
|
179
|
+
static func md5(_ input: String) -> String {
|
|
180
|
+
let data = Data(input.utf8)
|
|
181
|
+
var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
|
|
182
|
+
data.withUnsafeBytes { CC_MD5($0.baseAddress, CC_LONG(data.count), &digest) }
|
|
183
|
+
return digest.map { String(format: "%02x", $0) }.joined()
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
static func sha256(_ input: String) -> String {
|
|
187
|
+
SHA256.hash(data: Data(input.utf8))
|
|
188
|
+
.compactMap { String(format: "%02x", $0) }.joined()
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// XCTest (mandatory)
|
|
193
|
+
final class CryptoUtilsTests: XCTestCase {
|
|
194
|
+
func testMD5MatchesOriginal() {
|
|
195
|
+
XCTAssertEqual(CryptoUtils.md5("test"), "098f6bcd4621d373cade4e832627b4f6")
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
> ⚠️ Crypto functions MUST produce identical output. Test with known pairs from original app.
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## ✅ Checkpoint (After each feature)
|
|
205
|
+
|
|
206
|
+
```markdown
|
|
207
|
+
## ✅ Feature Complete: [Feature Name]
|
|
208
|
+
|
|
209
|
+
### Files created:
|
|
210
|
+
- Domain/Models/User.swift
|
|
211
|
+
- Domain/Repositories/AuthRepository.swift
|
|
212
|
+
- Domain/UseCases/LoginUseCase.swift
|
|
213
|
+
- Data/Network/Endpoints/AuthEndpoint.swift
|
|
214
|
+
- Data/Network/DTOs/LoginRequest.swift, LoginResponse.swift
|
|
215
|
+
- Data/Repositories/AuthRepositoryImpl.swift
|
|
216
|
+
- Presentation/Screens/Auth/LoginScreen.swift
|
|
217
|
+
- Presentation/Screens/Auth/LoginViewModel.swift
|
|
218
|
+
|
|
219
|
+
### Resources extracted:
|
|
220
|
+
- [only what was needed]
|
|
221
|
+
|
|
222
|
+
### Tests:
|
|
223
|
+
- [ ] Crypto utils verified
|
|
224
|
+
- [ ] API contract matches original
|
|
225
|
+
|
|
226
|
+
### ⏭️ Next Feature: [Name]
|
|
227
|
+
→ Return to Phase 2 (Blueprint)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 🔄 Loop
|
|
233
|
+
|
|
234
|
+
```
|
|
235
|
+
Phase 2 (Blueprint Feature X) → Phase 3 (Build Feature X) → Checkpoint
|
|
236
|
+
↓
|
|
237
|
+
Phase 2 (Blueprint Feature Y) → Phase 3 (Build Feature Y) → Checkpoint
|
|
238
|
+
↓
|
|
239
|
+
... → Final Parity Check
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## ✅ Final Parity Check
|
|
245
|
+
|
|
246
|
+
1. **API Parity** — all endpoints match
|
|
247
|
+
2. **Data Parity** — crypto output identical
|
|
248
|
+
3. **UI Parity** — screen comparison
|
|
249
|
+
4. **Build & Test:**
|
|
250
|
+
```bash
|
|
251
|
+
xcodebuild -scheme App -destination 'generic/platform=iOS' build
|
|
252
|
+
xcodebuild -scheme App -destination 'platform=iOS Simulator,name=iPhone 16' test
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
*Phase 3: Implementation — One feature at a time, guided by Blueprint*
|