--- name: analyze-logs description: Analyze Tangem app user logs — extract device info, navigation path, errors, and key events timeline. Use when user provides a log file for bug investigation. allowed-tools: Read, Grep argument-hint: /path/to/logfile.txt [/path/to/logs.rtf] [--no-secrets-audit] --- Analyze the Tangem app user log file at path: `$ARGUMENTS` ## File Input The user provides one or two file paths: - **Log file** (`.txt`) — main application log, always required - **User info file** (`.rtf` or `.txt`) — optional, contains card/device/error info from the user's feedback email If two paths are provided, the first is the log file and the second is the user info file. **If only the log file is provided**, ask the user if they have a user info file (`logs.rtf` or `logs.txt`). If they don't have it or don't respond, fill Device Context, Card Info, and Transaction Context sections from the log file data (Steps 2+3). Mark fields that could not be determined as "N/A". ## User Info File (logs.rtf / logs.txt) If a user info file is provided, Read it and extract the plain text fields. The file contains structured key-value pairs like: ``` Card ID: AF36000002151580 Firmware version: 6.33r Linked cards count: 2 Has seed phrase: true Signed hashes [secp256k1]: 0 ---------- Blockchain: Polygon Explorer link: https://polygonscan.com/address/0x... Derivation path: m/44'/60'/0'/0/0 Host: https://rpc-mainnet.matic.quiknode.pro/ Token: USDC Error: Could not construct a recoverable key. ---------- Source address: 0x... Destination address: 0x... Amount: 11.319684 Fee: 0.004973 ---------- Phone model: SM-S921B OS version: 36 App version: 5.34.1 ``` Extract all fields and include them in the **Device Context**, **Card Info**, and **Analysis Summary** sections of the report. If the RTF contains an `Error:` field, treat it as a key clue for the investigation. Note: RTF files contain formatting markup (`\cb3`, `\cf4`, `{\field{...}}`). Ignore all RTF tags — only extract the plain text values after each colon. ## Log Format Each line follows the pattern: ``` DD.MM HH:MM:SS.mmm: TAG Message ``` - Date format: `DD.MM` (day.month), no year — infer from context - Multi-line entries (JSON bodies, stack traces) continue without the timestamp prefix - Sensitive data is masked with `******` - Continuation lines may start with `|` for structured data: `|- Duration millis: 300000` ## Analysis Steps Use `head_limit` on every Grep call to protect context from overload. ### Step 1: Setup 1. **Log time range:** Read the first and last lines with dates (format `DD.MM`) 2. **Ask the user** (report time range, then ask): - Date range to focus on (or "all" for the full file) - Focus area: `Wallet`, `WalletConnect`, `Express (Onramp/Buy, Offramp/Sell, Swap/Exchange)`, `TangemPay`, `Feed`, `Markets`, `Settings`, `Referral`, `Staking`, `Onboarding`, `Send/Transactions`, `NFT`, or `all` - Remember the chosen area as **FOCUS_AREA** 3. **Determine line range** (skip if "all"): - Parse input into `DD.MM` patterns (`10-13.03` → start `10.03`, end `13.03`; `last day` → last date; `last 3 days` → 3 days before last) - Find **START_LINE**: Grep `^START_DATE` (head_limit: 1, -n: true) - Find **END_LINE**: Grep `^NEXT_DATE` (head_limit: 1, -n: true). If not found, END_LINE = end of file - Report: "Focusing on lines START_LINE–END_LINE covering DD.MM–DD.MM" ### Steps 2+3+4+5+6: Main Analysis (all in parallel) Launch ALL Grep calls below in parallel. Steps 2+3 search the **full file** (device info may be before the date range). Steps 4+5+6 use `offset: START_LINE` to stay within the date range. **Device Context (full file):** - `PATCH.*user-wallets/applications` (head_limit: 5, -A 10) — Read JSON body to extract `systemVersion`, `version`, `language`, `timezone` - `ip_address` (head_limit: 5, -A 20) — extract `alpha2`, `country`, `isBuyAllowed`, `isSellAllowed` **Card Info (full file):** - `CardSDK_Tlv.*TAG_Firmware` (head_limit: 20) - `CardSDK_Tlv.*TAG_SettingsMask` (head_limit: 20) - `CardSDK_Tlv.*TAG_IsActivated` (head_limit: 20) - `CardSDK_Tlv.*TAG_ManufacturerName` (head_limit: 20) **Navigation (offset: START_LINE):** - `AppRouter` (head_limit: 200) — if FOCUS_AREA is `all` or navigation-heavy (Wallet, Onboarding, Send/Transactions), also Read `.claude/docs/navigation-graph.md` to cross-reference routes **Errors (offset: START_LINE, head_limit: 50 each, -n: true):** - HTTP errors: `<-- [45]\d{2}` - Domain errors: `DomainError` - App exceptions: `\bException\b` - Biometric errors: `onAuthenticationError` - Tangem Pay errors: `Failed checkCustomerWallet` **Session timeline (offset: START_LINE, head_limit: 50 each):** - `MainActivity.*onCreate` — app session start - `MainActivity.*Splash screen` — splash screen installed/dismissed - `MainActivity.*onNewIntent` — deep link or push notification - `CardSDK_Session.*start card session` — NFC session starts **Secrets & PII Audit (full file, head_limit: 20 each, -n: true):** Skip this entire group if `--no-secrets-audit` is in arguments. - API key leak in URL: `[?&](api[_-]?key|apiKey|access_token|token|secret)=(?!\*+)[^&\s]{8,}` - Bearer token: `Bearer\s+[A-Za-z0-9._\-]{20,}` - JWT: `eyJ[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+\.[A-Za-z0-9_\-]+` - Authorization header: `(?i)authorization:\s*\S+` - Critical PII in JSON: `"(privateKey|mnemonic|seedPhrase|private_key|seed_phrase)"\s*:\s*"[^"]+"` - card_public_key in JSON: `"card_public_key"\s*:\s*"[^"]{40,}"` - FCM push token: `:APA91[A-Za-z0-9_\-]{100,}` - xprv/tprv extended private key: `\b[xytzuv]prv[A-Za-z0-9]{100,}` - Suspicious long hex in URL path: `https?://[^?\s]+/[A-Fa-f0-9]{32,}\b` - Masking health check: count of `\*{6,}` — if 0 in a build that should mask, flag pipeline broken **Error filtering:** When processing error results, skip these noisy matches: - `java.io.IOException: Canceled` — normal request cancellation - `HttpException(code=304` — HTTP "Not Modified" - Bare stacktrace lines starting with `\tat` - `<-- HTTP FAILED: java.io.IOException: Canceled` ### Step 6.5: Masking Consistency Check Skip if `--no-secrets-audit` in arguments. Run sequentially after the parallel batch (needs results from the masked-endpoint grep). 1. Grep `https?://[^/\s]+/[^\s*]*\*{6,}` (full file, head_limit: 50) — collect all URLs where a path segment is masked 2. For each unique `host + path-prefix-before-mask`, derive the prefix string 3. For each prefix, Grep the prefix followed by a non-`*` character (`[^*\s]`, head_limit: 20) - If hits found → masking inconsistency: same endpoint has both masked and unmasked variants - Record the prefix, count of masked hits, count of unmasked hits, first unmasked line number ### Step 7: Deep Dive For each significant error found above: 1. Note the error's line number from Grep output (`-n: true`) 2. Use Read with `offset: ERROR_LINE - 100, limit: 200` to get ~200 lines of context 3. In that context, look for navigation events, API calls, and redux actions ## Key Tags Reference | Tag | Purpose | |-----|---------| | `MainActivity` | Activity lifecycle, splash screen, onNewIntent | | `AppRouter` | Navigation: Push, Pop, Replace | | `NetworkLogs` | HTTP requests/responses (OkHttp) | | `BlockchainSDK_NETWORK` | Blockchain RPC calls | | `CardSDK_Tlv` | NFC card data (firmware, settings) | | `CardSDK_Session` | NFC session lifecycle | | `CardSDK_Biometric` | Biometric authentication | ## Common Error Patterns | Pattern | Meaning | |---------|---------| | `HttpException(code=4xx/5xx, errorBody={...})` | API error with structured body | | `DomainError(description=...)` | App-level domain error | | `<-- HTTP FAILED: java.io.IOException: Canceled` | Cancelled network request (noise) | | `<-- 429` | Rate limiting | | `onAuthenticationError` | Biometric auth failure | ## Output Template Structure your report EXACTLY as follows: ``` # Log Analysis Report ## Device Context | Parameter | Value | |-----------|-------| | App version | ... | | Android version | ... | | Phone model | ... (from logs.rtf if available) | | Language | ... | | Timezone | ... | | Country | ... | | Log time range | DD.MM HH:MM — DD.MM HH:MM | ## Card Info | Parameter | Value | |-----------|-------| | Card ID | ... (from logs.rtf if available) | | Firmware | ... | | Manufacturer | ... | | Is activated | ... | | Linked cards | ... (from logs.rtf if available) | | Has seed phrase | ... (from logs.rtf if available) | ## Transaction Context (from logs.rtf, if available) | Parameter | Value | |-----------|-------| | Blockchain | ... | | Token | ... | | Source address | ... | | Destination address | ... | | Amount | ... | | Fee | ... | | Error | ... | ## Navigation Path 1. [HH:MM:SS] Screen (Push/Pop/Replace) 2. ... **Summary:** Brief description of the user's journey. ## Errors Found ### HTTP Errors | Time | URL | Status | Details | |------|-----|--------|---------| ### Domain Errors | Time | Component | Error | |------|-----------|-------| ### Other Errors | Time | Type | Details | |------|------|---------| ## Key Events Timeline | Time | Event | Details | |------|-------|---------| (chronological: app starts, card sessions, navigation, errors, notable API calls) ## Secrets & PII Audit Omit this section entirely if `--no-secrets-audit` was passed. ### Health Check - Total masked tokens (`******`) in log: **N** - If N = 0 in a build expected to mask, flag: "masking pipeline may be broken" ### Confirmed Leaks (CRITICAL / HIGH) | Line | Severity | Type | Matched (first 16 chars + `…`) | Context | |------|----------|------|--------------------------------|---------| ### Masking Inconsistencies | Endpoint Prefix | Masked Hits | Unmasked Hits | First Unmasked Line | |-----------------|-------------|---------------|---------------------| ### Suspected Leaks (MEDIUM / LOW) | Line | Severity | Type | Pattern Matched | Why Suspect | |------|----------|------|-----------------|-------------| **Severity legend:** - **CRITICAL** — private key / mnemonic / xprv in clear text - **HIGH** — API key / bearer / JWT / card_public_key visible - **MEDIUM** — push token, card_id, persistent identifiers - **LOW** — heuristic patterns that may be false positives (tx hash, content hash) **Output rules:** - Never include the full matched value — always truncate to 16 chars + `…` - For LOW severity, add a "Why Suspect" column explaining typical false positives - Skip matches from these known-public Tangem endpoints: `/v1/coins/settings`, `/v1/geo`, `/v1/currencies`, `/v1/hot_crypto` ## Analysis Summary (2-3 paragraphs: what the user was doing, what broke, probable cause, recommendations. If FOCUS_AREA was specified, emphasize errors, navigation, and API calls related to that area.) ``` If a section has no data, write "None found" instead of omitting it.