@buivietphi/skill-mobile-mt 2.0.1 → 2.1.0

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.
@@ -0,0 +1,426 @@
1
+ # Mobile i18n & Localization
2
+
3
+ > Multi-language support for React Native, Flutter, iOS, Android.
4
+ > Covers: setup, translation management, RTL, date/number formatting, dynamic locale switching.
5
+
6
+ ---
7
+
8
+ ## Decision Matrix — Pick Your Stack
9
+
10
+ ```
11
+ PLATFORM → RECOMMENDED LIBRARY
12
+ ──────────────────────────────────────────────────────────────────
13
+ React Native → i18next + react-i18next (most popular, flexible)
14
+ OR expo-localization + custom (Expo projects)
15
+
16
+ Flutter → slang (type-safe, code generation) ← recommended
17
+ OR flutter_localizations + .arb files (official)
18
+ OR easy_localization (simple)
19
+
20
+ iOS Native → .xcstrings / Localizable.strings (built-in Xcode)
21
+ Android Native → strings.xml per locale (built-in Android Studio)
22
+ ```
23
+
24
+ ---
25
+
26
+ ## React Native — i18next
27
+
28
+ ### Setup
29
+
30
+ ```bash
31
+ npm install i18next react-i18next
32
+ npm install @react-native-async-storage/async-storage # for locale persistence
33
+ # or with expo:
34
+ npx expo install expo-localization
35
+ ```
36
+
37
+ ### File Structure
38
+
39
+ ```
40
+ src/
41
+ ├── i18n/
42
+ │ ├── index.ts ← i18next init
43
+ │ ├── en.json ← English (base language)
44
+ │ ├── vi.json ← Vietnamese
45
+ │ ├── ja.json ← Japanese
46
+ │ ├── ar.json ← Arabic (RTL)
47
+ │ └── types.ts ← TypeScript type for translation keys
48
+ ```
49
+
50
+ ### Translation Files
51
+
52
+ ```json
53
+ // i18n/en.json
54
+ {
55
+ "common": {
56
+ "ok": "OK",
57
+ "cancel": "Cancel",
58
+ "loading": "Loading...",
59
+ "error": "Something went wrong",
60
+ "retry": "Try again",
61
+ "empty": "No results found"
62
+ },
63
+ "auth": {
64
+ "login": "Login",
65
+ "logout": "Logout",
66
+ "email": "Email address",
67
+ "password": "Password",
68
+ "forgotPassword": "Forgot password?",
69
+ "errors": {
70
+ "invalidEmail": "Please enter a valid email",
71
+ "wrongPassword": "Incorrect password"
72
+ }
73
+ },
74
+ "profile": {
75
+ "title": "My Profile",
76
+ "greeting": "Hello, {{name}}!",
77
+ "itemCount": "{{count}} item",
78
+ "itemCount_other": "{{count}} items"
79
+ }
80
+ }
81
+ ```
82
+
83
+ ```json
84
+ // i18n/vi.json
85
+ {
86
+ "common": {
87
+ "ok": "Đồng ý",
88
+ "cancel": "Hủy",
89
+ "loading": "Đang tải...",
90
+ "error": "Có lỗi xảy ra",
91
+ "retry": "Thử lại",
92
+ "empty": "Không có kết quả"
93
+ },
94
+ "auth": {
95
+ "login": "Đăng nhập",
96
+ "logout": "Đăng xuất",
97
+ "email": "Địa chỉ email",
98
+ "password": "Mật khẩu",
99
+ "forgotPassword": "Quên mật khẩu?",
100
+ "errors": {
101
+ "invalidEmail": "Vui lòng nhập email hợp lệ",
102
+ "wrongPassword": "Mật khẩu không đúng"
103
+ }
104
+ },
105
+ "profile": {
106
+ "title": "Hồ sơ của tôi",
107
+ "greeting": "Xin chào, {{name}}!",
108
+ "itemCount": "{{count}} mục"
109
+ }
110
+ }
111
+ ```
112
+
113
+ ### i18next Init
114
+
115
+ ```typescript
116
+ // i18n/index.ts
117
+ import i18n from 'i18next';
118
+ import { initReactI18next } from 'react-i18next';
119
+ import * as Localization from 'expo-localization';
120
+ import MMKV from '../storage'; // your MMKV wrapper
121
+
122
+ import en from './en.json';
123
+ import vi from './vi.json';
124
+ import ar from './ar.json';
125
+
126
+ const LANGUAGE_KEY = 'user_language';
127
+
128
+ export const SUPPORTED_LANGUAGES = ['en', 'vi', 'ja', 'ar'] as const;
129
+ export type Language = typeof SUPPORTED_LANGUAGES[number];
130
+
131
+ // Get saved or device language
132
+ const savedLang = MMKV.getString(LANGUAGE_KEY);
133
+ const deviceLang = Localization.getLocales()[0]?.languageCode ?? 'en';
134
+ const initialLang = savedLang ?? (SUPPORTED_LANGUAGES.includes(deviceLang as Language) ? deviceLang : 'en');
135
+
136
+ i18n.use(initReactI18next).init({
137
+ resources: { en: { translation: en }, vi: { translation: vi }, ar: { translation: ar } },
138
+ lng: initialLang,
139
+ fallbackLng: 'en',
140
+ interpolation: { escapeValue: false },
141
+ });
142
+
143
+ export function changeLanguage(lang: Language) {
144
+ i18n.changeLanguage(lang);
145
+ MMKV.setString(LANGUAGE_KEY, lang); // persist choice
146
+ }
147
+
148
+ export default i18n;
149
+ ```
150
+
151
+ ### Usage in Components
152
+
153
+ ```typescript
154
+ import { useTranslation } from 'react-i18next';
155
+ import { I18nManager } from 'react-native';
156
+
157
+ export function ProfileScreen() {
158
+ const { t, i18n } = useTranslation();
159
+ const isRTL = I18nManager.isRTL;
160
+
161
+ return (
162
+ <View style={[styles.container, isRTL && styles.rtl]}>
163
+ <Text>{t('profile.title')}</Text>
164
+ <Text>{t('profile.greeting', { name: 'Phi' })}</Text>
165
+ <Text>{t('profile.itemCount', { count: 5 })}</Text>
166
+
167
+ {/* Language switcher */}
168
+ <Button title="Tiếng Việt" onPress={() => changeLanguage('vi')} />
169
+ <Button title="English" onPress={() => changeLanguage('en')} />
170
+ </View>
171
+ );
172
+ }
173
+
174
+ // TypeScript type-safe keys (optional but recommended)
175
+ // Generate from en.json with i18next-resources-for-ts
176
+ ```
177
+
178
+ ### RTL Support (Arabic, Hebrew)
179
+
180
+ ```typescript
181
+ // App.tsx — apply RTL on init
182
+ import { I18nManager } from 'react-native';
183
+ import * as Updates from 'expo-updates';
184
+
185
+ function applyRTL(language: string) {
186
+ const isRTL = language === 'ar' || language === 'he';
187
+
188
+ if (I18nManager.isRTL !== isRTL) {
189
+ I18nManager.allowRTL(isRTL);
190
+ I18nManager.forceRTL(isRTL);
191
+ // Requires reload to take effect
192
+ Updates.reloadAsync(); // Expo
193
+ // RNRestart.Restart(); // react-native-restart (bare RN)
194
+ }
195
+ }
196
+
197
+ // RTL-aware styles
198
+ const styles = StyleSheet.create({
199
+ row: {
200
+ flexDirection: I18nManager.isRTL ? 'row-reverse' : 'row',
201
+ },
202
+ text: {
203
+ textAlign: I18nManager.isRTL ? 'right' : 'left',
204
+ writingDirection: I18nManager.isRTL ? 'rtl' : 'ltr',
205
+ },
206
+ });
207
+ ```
208
+
209
+ ### Date / Number Formatting
210
+
211
+ ```typescript
212
+ // Use Intl API (built into Hermes/V8)
213
+ const locale = i18n.language;
214
+
215
+ // Date
216
+ const formatDate = (date: Date) =>
217
+ new Intl.DateTimeFormat(locale, { dateStyle: 'medium', timeStyle: 'short' }).format(date);
218
+
219
+ // Number / Currency
220
+ const formatCurrency = (amount: number, currency = 'USD') =>
221
+ new Intl.NumberFormat(locale, { style: 'currency', currency }).format(amount);
222
+
223
+ // Relative time (2 days ago, in 3 hours)
224
+ const formatRelative = (date: Date) =>
225
+ new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }).format(
226
+ Math.round((date.getTime() - Date.now()) / 86400000), 'day'
227
+ );
228
+
229
+ // Usage
230
+ formatDate(new Date()); // "Jan 15, 2025, 2:30 PM"
231
+ formatCurrency(99.99); // "$99.99" / "99,99 €"
232
+ formatRelative(yesterday); // "yesterday" / "hôm qua"
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Flutter — slang (Recommended)
238
+
239
+ ### Setup
240
+
241
+ ```yaml
242
+ # pubspec.yaml
243
+ dependencies:
244
+ flutter_localizations:
245
+ sdk: flutter
246
+ slang: ^4.0.0
247
+ slang_flutter: ^4.0.0
248
+
249
+ dev_dependencies:
250
+ slang_build_runner: ^4.0.0
251
+ build_runner: ^2.0.0
252
+
253
+ flutter:
254
+ generate: true
255
+ ```
256
+
257
+ ### Translation Files
258
+
259
+ ```json
260
+ // assets/i18n/en.i18n.json
261
+ {
262
+ "common": {
263
+ "ok": "OK",
264
+ "cancel": "Cancel",
265
+ "loading": "Loading..."
266
+ },
267
+ "auth": {
268
+ "login": "Login",
269
+ "greeting": "Hello, $name!",
270
+ "itemCount(n)": {
271
+ "one": "$n item",
272
+ "other": "$n items"
273
+ }
274
+ }
275
+ }
276
+ ```
277
+
278
+ ```json
279
+ // assets/i18n/vi.i18n.json
280
+ {
281
+ "common": {
282
+ "ok": "Đồng ý",
283
+ "cancel": "Hủy",
284
+ "loading": "Đang tải..."
285
+ },
286
+ "auth": {
287
+ "login": "Đăng nhập",
288
+ "greeting": "Xin chào, $name!",
289
+ "itemCount(n)": "$n mục"
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Generate + Use
295
+
296
+ ```bash
297
+ dart run build_runner build
298
+ ```
299
+
300
+ ```dart
301
+ // main.dart
302
+ import 'package:flutter_localizations/flutter_localizations.dart';
303
+ import 'i18n/strings.g.dart'; // generated
304
+
305
+ void main() {
306
+ WidgetsFlutterBinding.ensureInitialized();
307
+ LocaleSettings.useDeviceLocale(); // or .setLocale(AppLocale.vi)
308
+ runApp(TranslationProvider(child: MyApp()));
309
+ }
310
+
311
+ class MyApp extends StatelessWidget {
312
+ Widget build(BuildContext context) => MaterialApp(
313
+ locale: TranslationProvider.of(context).flutterLocale,
314
+ supportedLocales: AppLocaleUtils.supportedLocales,
315
+ localizationsDelegates: GlobalMaterialLocalizations.delegates,
316
+ home: HomeScreen(),
317
+ );
318
+ }
319
+
320
+ // Usage — fully type-safe, autocomplete
321
+ final t = Translations.of(context);
322
+
323
+ Text(t.common.ok)
324
+ Text(t.auth.greeting(name: 'Phi'))
325
+ Text(t.auth.itemCount(n: 5))
326
+
327
+ // Change language
328
+ LocaleSettings.setLocale(AppLocale.vi);
329
+ ```
330
+
331
+ ---
332
+
333
+ ## iOS Native (Xcode .xcstrings)
334
+
335
+ ```
336
+ Localizable.xcstrings (modern, Xcode 15+):
337
+ - Edit in Xcode string catalog UI
338
+ - Automatic plural rules per language
339
+ - Supports all Apple platforms
340
+
341
+ File structure:
342
+ App/
343
+ ├── en.lproj/Localizable.xcstrings ← base language
344
+ ├── vi.lproj/Localizable.xcstrings
345
+ └── ar.lproj/Localizable.xcstrings
346
+ ```
347
+
348
+ ```swift
349
+ // Usage
350
+ Text(String(localized: "auth.login")) // SwiftUI (auto-localizes)
351
+ label.text = NSLocalizedString("auth.login", comment: "") // UIKit
352
+
353
+ // With interpolation
354
+ Text("profile.greeting \(userName)")
355
+ // Localizable.xcstrings: "profile.greeting %@" → "Xin chào, %@!"
356
+
357
+ // Date/Number formatting
358
+ let formatted = Date().formatted(.dateTime.month(.wide).day().year())
359
+ let price = amount.formatted(.currency(code: "VND").locale(Locale(identifier: "vi_VN")))
360
+ ```
361
+
362
+ ---
363
+
364
+ ## Android Native (strings.xml)
365
+
366
+ ```xml
367
+ <!-- res/values/strings.xml (English, default) -->
368
+ <resources>
369
+ <string name="common_ok">OK</string>
370
+ <string name="auth_login">Login</string>
371
+ <string name="profile_greeting">Hello, %s!</string>
372
+ <plurals name="profile_item_count">
373
+ <item quantity="one">%d item</item>
374
+ <item quantity="other">%d items</item>
375
+ </plurals>
376
+ </resources>
377
+
378
+ <!-- res/values-vi/strings.xml (Vietnamese) -->
379
+ <resources>
380
+ <string name="common_ok">Đồng ý</string>
381
+ <string name="auth_login">Đăng nhập</string>
382
+ <string name="profile_greeting">Xin chào, %s!</string>
383
+ <plurals name="profile_item_count">
384
+ <item quantity="other">%d mục</item>
385
+ </plurals>
386
+ </resources>
387
+ ```
388
+
389
+ ```kotlin
390
+ // Usage
391
+ getString(R.string.auth_login)
392
+ getString(R.string.profile_greeting, "Phi")
393
+ resources.getQuantityString(R.plurals.profile_item_count, 5, 5)
394
+ ```
395
+
396
+ ---
397
+
398
+ ## i18n Checklist
399
+
400
+ ```
401
+ SETUP:
402
+ □ Translation keys are namespaced (auth.login, not just "login")
403
+ □ Base language file has ALL keys
404
+ □ Missing key fallback configured (falls back to English)
405
+ □ Language preference persisted on device (MMKV/SharedPreferences)
406
+ □ Language detected from device locale on first launch
407
+
408
+ CONTENT:
409
+ □ No hardcoded strings in components (all through t() / getString)
410
+ □ Plurals handled correctly (1 item vs 2 items)
411
+ □ Interpolation used for dynamic values (name, count)
412
+ □ Date/number/currency formatted per locale (Intl API)
413
+
414
+ RTL (if supporting Arabic/Hebrew):
415
+ □ I18nManager.forceRTL() applied and app reloaded
416
+ □ flexDirection mirrors on RTL
417
+ □ textAlign mirrors on RTL
418
+ □ Icons and chevrons mirror on RTL
419
+ □ Back navigation arrow mirrors on RTL
420
+
421
+ TESTING:
422
+ □ Test with locale set to each supported language
423
+ □ Test with system language set to unsupported → falls back to English
424
+ □ Test RTL layout on Arabic device or simulator
425
+ □ Test long strings (German/Finnish) don't break UI layout
426
+ ```
@@ -64,40 +64,138 @@
64
64
  ```xml
65
65
  <think>
66
66
  BUG: [description]
67
- FILE: [path]
67
+ ERROR MESSAGE: [paste exact error]
68
+
69
+ ⛔ STOP — CLASSIFY + SEARCH PROJECT FIRST (before ANY analysis):
70
+
71
+ <error_classification>
72
+ TYPE: [RUNTIME CRASH / BUILD ERROR / TYPE MISMATCH / NETWORK ERROR /
73
+ RENDER ERROR / NAVIGATION ERROR / PERFORMANCE / STATE ERROR /
74
+ NATIVE ERROR / MEMORY ERROR / INVESTIGATION]
75
+
76
+ SEARCH STRATEGY based on type:
77
+ → RUNTIME/STATE/RENDER/NAVIGATION → Search src/ FIRST → then trace outward
78
+ → BUILD/NATIVE → Search config files FIRST (tsconfig/gradle/Pod/pubspec)
79
+ → NETWORK/API → Search API service files → then .env → then interceptors
80
+ → INVESTIGATION → Search by feature name → read → report (don't fix yet)
81
+
82
+ If complex bug → Read shared/debugging-intelligence.md for pattern match
83
+ </error_classification>
84
+
85
+ <project_search>
86
+ STEP 1: Extract keywords from error:
87
+ → File/path in stack trace: [extract]
88
+ → Function/class/component name: [extract]
89
+ → Module/package name: [extract]
90
+ → Line number: [extract if available]
91
+ → Error code / HTTP status: [extract if available]
92
+
93
+ STEP 2: Filter noise from log (if user pasted log):
94
+ → SKIP: node_modules/*, React internals, engine frames
95
+ → FOCUS: lines with src/ paths, "Error:", "Caused by:", YOUR component names
96
+
97
+ STEP 3: Search project source code (MANDATORY):
98
+ → Grep "[keyword]" src/ ← ALWAYS start here (unless BUILD error)
99
+ → Grep "[function_name]" src/ ← find the actual function
100
+ → Glob "**/*[ComponentName]*" ← find the actual file
101
+ → Results: [list files found]
102
+
103
+ STEP 4: Read matched files (TOP 3-5):
104
+ → Read [file1] — [what I found: actual code, types, imports]
105
+ → Read [file2] — [what I found: related logic, callers]
106
+ → Read [file3] — [what I found: state/store connected to this]
107
+
108
+ ⛔ If I skipped Step 1-4 → GO BACK AND DO THEM NOW
109
+ ⛔ If I found 0 results in src/ → widen: lib/ → app/ → project root
110
+ </project_search>
68
111
 
69
112
  <source_verification>
70
- ⚠️ BEFORE analyzing verify I have real data:
71
- - [ ] Read the actual file (not guessing from error message)
72
- - [ ] Verified function/class names exist (grep)
113
+ ⚠️ Verify I have REAL project data (not assumptions):
114
+ - [ ] Classified error type and picked correct search strategy
115
+ - [ ] Filtered noise from log (if applicable)
116
+ - [ ] Searched src/ with Grep for error keywords → found files
117
+ - [ ] Read the actual file(s) where bug occurs
118
+ - [ ] Verified function/class names exist in project (grep result)
73
119
  - [ ] Checked package versions in package.json/pubspec.yaml
74
120
  - [ ] Identified data types from actual code (not assumed)
121
+ - [ ] Traced the call chain: who calls this → what it returns
75
122
  </source_verification>
76
123
 
77
- <context_needed>
78
- - Read [file] to understand current implementation
79
- - Grep for similar patterns: grep "[pattern]" src/
80
- - Check imports and dependencies
81
- </context_needed>
82
-
83
- <root_cause>
84
- [Analyze AFTER loading context - don't guess]
85
- - What code is executed?
86
- - What values are passed?
87
- - What conditions are checked?
88
- SOURCE: [file:line where the bug is cite exact location]
89
- </root_cause>
124
+ <root_cause_tracing>
125
+ NO FIXES WITHOUT ROOT CAUSE INVESTIGATION FIRST
126
+
127
+ STEP 1 IMMEDIATE CAUSE (what throws):
128
+ - Error type: [from classification above]
129
+ - Crash/error at: [file:line from project search]
130
+ - What code does at that line: [describe from reading]
131
+ - What value is wrong: [actual vs expected]
132
+
133
+ STEP 2 TRACE BACKWARD (what called this):
134
+ - Who calls this function? → [grep callers in src/]
135
+ - What data does caller pass? [trace data origin]
136
+ - Go up one level: who calls the caller? → [trace further]
137
+
138
+ STEP 3 — ROOT CAUSE (where chain breaks):
139
+ - Root cause at: [file:line — where correct data becomes incorrect]
140
+ - WHY it fails: [based on actual code read, NOT guess]
141
+ - Does this match a known pattern? → [check debugging-intelligence.md if loaded]
142
+ - Does root cause explain ALL symptoms? YES/NO
143
+ → If NO → theory is wrong → re-trace from Step 2
144
+ </root_cause_tracing>
145
+
146
+ <working_example>
147
+ Search for similar working code in SAME project:
148
+ → Grep for similar pattern that works: [search term]
149
+ → Found working example at: [file:line] (or "none found")
150
+ → Differences between broken vs working:
151
+ 1. [difference]
152
+ 2. [difference]
153
+ → The fix should align broken code with working pattern
154
+ </working_example>
155
+
156
+ <hypothesis>
157
+ ⛔ 1 HYPOTHESIS → 1 MINIMAL CHANGE → VERIFY
158
+
159
+ HYPOTHESIS: [specific theory based on root cause]
160
+ CHANGE: [smallest possible change to test this — 1 change only]
161
+ EXPECTED RESULT: [what should happen if hypothesis is correct]
162
+
163
+ ⛔ If this fails → REVERT → form NEW hypothesis (never stack fixes)
164
+ ⛔ If 3 hypotheses fail → STOP → question architecture
165
+ </hypothesis>
90
166
 
91
167
  <fix>
92
- [Specific change with code snippet]
168
+ [Specific change with code snippet — before → after]
93
169
 
94
170
  WHY IT WORKS:
95
- [Explain the fix based on root cause]
171
+ [Explain based on root cause tracing — not guess]
96
172
  SOURCE: [where this fix pattern comes from — project code / skill file / official docs]
173
+
174
+ DEFENSE IN DEPTH (make bug structurally impossible):
175
+ - Layer 1 (input): [validation added]
176
+ - Layer 2 (state): [guard added]
177
+ - Layer 3 (render): [null check / fallback added]
97
178
  </fix>
98
179
 
180
+ <verification>
181
+ ⛔ NO COMPLETION CLAIMS WITHOUT EVIDENCE
182
+
183
+ 🚩 Anti-rationalization check:
184
+ - Am I saying "should work now" without running it? → RUN IT
185
+ - Am I "confident" without evidence? → PROVE IT
186
+ - Am I stacking 3+ changes? → REVERT. 1 change only.
187
+
188
+ Evidence:
189
+ - [ ] Fix addresses root cause (not just symptoms)
190
+ - [ ] All symptoms explained by this root cause
191
+ - [ ] Working example pattern followed (if found)
192
+ - [ ] Defense-in-depth added at [N] layers
193
+ - [ ] Side effects checked (grep for other callers)
194
+ - [ ] Both platforms considered (iOS + Android)
195
+ </verification>
196
+
99
197
  <side_effects>
100
- - Files that import this: [list after grep]
198
+ - Files that import this: [list from grep results]
101
199
  - Tests affected: [list]
102
200
  - Platform-specific: iOS [impact] / Android [impact]
103
201
  </side_effects>
@@ -116,6 +214,64 @@ FILE: [path]
116
214
  </think>
117
215
  ```
118
216
 
217
+ ### Diagnostic Scan (user unsure / vague / "check this for me")
218
+
219
+ ```xml
220
+ <think>
221
+ USER SAID: [what user described or asked — could be vague]
222
+ AREA: [extract: screen name / feature name / module name / file name]
223
+
224
+ <area_identification>
225
+ What did user mention or show?
226
+ → Screen/feature name: [extract from user's words]
227
+ → File pasted/referenced: [if any]
228
+ → Behavior described: [if any]
229
+ → If unclear → I should ask: "Which screen or feature should I check?"
230
+ </area_identification>
231
+
232
+ <project_search>
233
+ Search broadly for this area:
234
+ → Grep "[feature]" src/ → found: [list files]
235
+ → Glob "**/*[ScreenName]*" → found: [list files]
236
+ → Also search: related hooks, services, stores, utils
237
+ → Total files to scan: [N files]
238
+ </project_search>
239
+
240
+ <diagnostic_scan>
241
+ For EACH file, run the checklist:
242
+
243
+ FILE: [file1:path]
244
+ □ Crash risks: [findings or "clean"]
245
+ □ Memory leaks: [findings or "clean"]
246
+ □ Race conditions: [findings or "clean"]
247
+ □ Security: [findings or "clean"]
248
+ □ Performance: [findings or "clean"]
249
+ □ UX/states: [findings or "clean"]
250
+ □ Data flow: [trace API → state → render — any break?]
251
+ □ Edge cases: [empty data? error response? offline? slow?]
252
+
253
+ FILE: [file2:path]
254
+ □ ... (repeat for each file)
255
+ </diagnostic_scan>
256
+
257
+ <report>
258
+ Scanned: [N files] in [area name]
259
+
260
+ 🔴 Issues found:
261
+ 1. [SEVERITY] [file:line] — [description]
262
+ 2. [SEVERITY] [file:line] — [description]
263
+
264
+ 🟡 Suspicious (might be intentional):
265
+ 1. [file:line] — [what looks off and why]
266
+
267
+ ✅ Looks good:
268
+ - [aspect that's well-implemented]
269
+
270
+ Recommendation: [what to fix first / what to investigate deeper]
271
+ </report>
272
+ </think>
273
+ ```
274
+
119
275
  **Example:**
120
276
  ```xml
121
277
  <think>