---
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 (`<prefix>[^*\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.