---
name: ds-mobile
description: Mobile app quality audit — 145+ rules across 13 domains with release-readiness scoring (Flutter, SwiftUI, Kotlin/Compose, React Native). Use when auditing a mobile app for quality or release readiness.
---

# /ds-mobile

Mobile apps ship with permission abuse, missing accessibility, hardcoded keys, and store-blocking issues that only surface during review. This skill catches them across 145+ rules before you submit.

**Mobile App Quality Audit** — 145+ rules across 13 domains with release readiness scoring. Flutter, SwiftUI, Kotlin/Compose, React Native.

## Triggers

- User runs `/ds-mobile`
- User asks to audit or review a mobile app (Flutter, React Native, iOS, Android)
- User asks about app store compliance, release readiness, or store submission
- Project contains `pubspec.yaml` (Flutter), `react-native` in `package.json`, `*.xcodeproj`, or Android `build.gradle` with `android {}` block

### Triggers — INVOKE / DON'T INVOKE

| INVOKE | DON'T INVOKE |
|---------|----------|
| "Flutter / iOS / Android / React-Native app audit" | "audit backend API" (→ ds-backend) |
| "mobile permissions audit", "release readiness for App Store" | "web-app privacy compliance" (→ ds-compliance --privacy) |
| "mobile UX (gestures, store presence, jank)" | "design system / token audit (cross-platform)" (→ ds-frontend) |
| "mobile-specific store rejection prevention" | "App Store submission metadata" (→ ds-launch) |

## Contract

- Audits mobile app quality; every finding cites file:line — never fabricates. Only touches mobile code; platform rules only on detected platforms.
- Standalone. Uses blueprint profile or `ds/audit/findings.md` when available; own analysis when absent.
- FRC+DSC enforced.
- Pre-existing / out-of-scope errors detected during work are NOT skipped — fixed inline or escalated with concrete blocker.

## Arguments

| Flag | Effect |
|------|--------|
| `--mode={x}` | `audit`, `audit+fix`, `quick-fix`, `release-ready` |
| `--scope={list}` | security, privacy, regulatory, store, ux, visual, a11y, arch, testing, perf, network, i18n, release, or `all` |
| `--platform={p}` | Override: `flutter`, `react-native`, `ios`, `android` |
| `--release-ready` | Shorthand for `--mode=release-ready` |
| `--skip-manual` | Skip manual gates (release-ready) |
| `--diff` | Compare with previous release report |
| `--resume` | Resume from `ds/audit/mobile.json` without prompting |
| `--clean` | Delete existing state, start fresh |

No flags → present mode selection.

## Modes

| Mode | Scope | Behavior |
|------|-------|----------|
| `audit` | All selected | Scan and report only |
| `audit+fix` | All selected | Scan, review, fix |
| `quick-fix` | All selected | Scan + auto-fix, minimal review |
| `release-ready` | security, privacy, regulatory, store, release, i18n, a11y | 100-point scoring + manual gates + live policy fetch |

## Delegation

**Owns:** mobile-security, mobile-privacy, mobile-regulatory, mobile-ux, mobile-store, mobile-permissions, mobile-release, mobile-visual | **Delegates:** none (authoritative for mobile projects) | **Receives:** ds-compliance → security / privacy / regulatory on mobile projects

## Execution Flow

```
Detect → Configure → [Architecture Discovery] → Scan → Report → [Fix/Score] → [Needs-Approval] → Summary
```

### Phase 1: Detect

**Recovery check:** DETECT `ds/audit/mobile.json`. Absent + no `--resume` → fresh. Absent + `--resume` → warn, fresh. Present + `--clean` → delete, fresh. Present → READ, verify `git_hash` vs HEAD. Mismatch → prompt `Resume anyway? [Y/n]` (honor `--resume`). Resume → RE-VERIFY `in_progress` phase (re-read files for pending findings, discard stale), skip `done` phases, announce `[MOB] Resuming from Phase {N}: {name}.` On successful Summary, delete state. Verify `ds/audit/*.json` in `.gitignore` on fresh start.

**State `data`:** `{ platform, mode, scopes_selected, scopes_done[], frameworks_detected[], findings[{id, severity, file, line, scope, disposition}], fix_progress, release_ready_score }`.

1. **Project detection.**

   | Platform | Detection |
   |----------|-----------|
   | Flutter | `pubspec.yaml` with `flutter:` |
   | React Native | `package.json` dep `react-native` |
   | iOS Native | `*.xcodeproj` or `Package.swift` |
   | Android Native | `build.gradle` with `android {}` |
   | Cross-platform | Multiple platform indicators |

2. **Platform confirmation.** Ambiguous → ask user.
3. **Findings file check:** `ds/audit/findings.md` fresh `git_hash` → read findings matching mobile scopes, skip redundant analysis. Stale/absent → own full analysis.
4. **IDU:** Profile → Config.data, Config.deploy, Current Scores, Type+Stack. Findings(mobile scopes) → verify + use. Absent → own analysis.
5. **Mode selection.** Ask or use flags: Audit / Audit & Fix / Quick Fix / Release Ready / Custom.
6. **Scope parsing.** Default: `audit` mode, all domains.
7. **Custom scope** (if Custom): ask for domains + mode.
8. **Regulatory framework detection** (security/regulatory/store/all):
   - Auto-detect framework indicators (GDPR, KVKK, CCPA, LGPD, PIPL, etc.)
   - Confirm with user
   - Rules tagged `[FRAMEWORK: X,Y]` only checked if at least one active
9. **Release-ready setup** (release-ready only):
   - Detect available platforms (`android/`, `ios/`); both → ask which
   - Release report path: `ds/mobile/release.json` (single file, committed, overwritten each run — `ds/<skill>/` user-facing operational namespace)
   - `--diff`: read previous content of `ds/mobile/release.json` before overwriting, compute diff in memory, present in chat. Trend over >1 run → `git log -- ds/mobile/release.json` is authoritative — never a directory of stale per-run reports.
   - Fetch live policy data (see references/scoring.md)

**Gate:** Platform identified; mode + scope confirmed; regulatory frameworks resolved. If fails → platform undetectable → prompt user (Flutter / RN / iOS / Android / Cross-platform), record in `state.data.platform`; mode/scope unconfirmed after prompt → default `audit` + `all`, warn; regulatory ambiguous → ask user to confirm before proceeding.

### Phase 2: Architecture Discovery [SKIP if 1-2 domains]

**When:** scope includes 3+ domains or `all`.

1. **Detect architecture:** pattern (Clean/MVVM/MVC), auth, state management, navigation, backend, offline, design system, testing, CI/CD, i18n, DI.
2. **Confirm with user.** Present for corrections.
3. **Classify rules:** CAT-1 = universal best practice, existing pattern misused, bug, security flaw (auto-fixable). CAT-2 = new layer/structure not in current architecture (needs approval). Category depends on architecture — user has Riverpod → UDF violation is CAT-1; no state management → adding it is CAT-2.
4. **Present ideal scenario.** Show CAT-1 + CAT-2 opportunities; ask which enhancements to include (default: none).
5. **Finalize scope:** all CAT-1 + only approved CAT-2; scope is fixed for entire audit.

**Critical rule:** CAT-2 fixes are NEVER applied without user approval.

**Gate:** Architecture confirmed; every rule classified CAT-1 / CAT-2; scope finalized with approved enhancements. If fails → no user corrections + no enhancement selections after one re-prompt → treat detected architecture as confirmed, classify unclassified rules as CAT-1, include zero CAT-2, record in `state.data.frameworks_detected`, proceed with note that architecture was auto-confirmed.

### Phase 3: Rule Loading

Load only reference files matching scope:

| Scope | Reference File |
|-------|---------------|
| security, privacy, regulatory, store | [rules-compliance.md](references/rules-compliance.md) |
| ux, visual, a11y | [rules-experience.md](references/rules-experience.md) |
| arch, testing, perf, network, i18n | [rules-engineering.md](references/rules-engineering.md) |
| release (release-ready) | [rules-release.md](references/rules-release.md) |
| release-ready scoring | [scoring.md](references/scoring.md) |

**Gate:** All reference files for in-scope domains loaded; unloadable domains marked N/A. If fails → file unloadable → mark domains N/A in `state.data.scopes_done` reason "reference file unavailable", skip in Phase 4, surface in Phase 9 summary as "domains skipped: {list} — reference files not found".

### Phase 4: Scan

1. **Findings file check:** `ds/audit/findings.md` fresh `git_hash` → read findings matching scopes; verify each (re-read file:line), skip verified; run full for uncovered.

**Large scope (3+ domains):** progress checklist + append findings to `ds/audit/findings.md` after each domain. Max 2 parallel scans.

**Per domain:** search files → search violations → read context to verify → skip unverifiable rules.

**arch scope mandatory checks ([references/principles.md §2](references/principles.md)):** evaluate widget / screen / view-model / repository layers against SOLID — SRP (widget changes for >1 reason: UI + state + I/O), OCP, LSP (subtype violates parent navigation contract), ISP (consumer forced to implement unused lifecycle hooks), DIP (UI imports concrete platform-channel instead of abstraction). GRASP — Information Expert, Low Coupling (>7 unrelated peer imports), High Cohesion. Cite principle by name.

**network + perf scope reliability checks ([references/principles.md §4](references/principles.md)):** flag missing — timeout on every API call, retry-with-exponential-backoff on transient failures, offline / slow-network graceful degradation, app-lifecycle handlers (background → foreground state restoration), idempotency keys on payment / order / write endpoints, structured logging surviving across app restart, fail-fast input validation at every boundary (deep links, push notifications, intent extras).

**Confidence:** HIGH = match + context verified. MEDIUM = pattern, ambiguous. LOW = heuristic.

**False-positive prevention:** never flag `// noqa`, `// intentional`, `// safe:`, `_` prefix, `TYPE_CHECKING`, test fixtures.

**Category assignment:** CAT-1 always reported; CAT-2 only if in approved enhancements.

**Recovery (context lost):** progress checklist → read `ds/audit/findings.md` → resume from first incomplete domain. Never re-scan completed.

**Gate:** Every in-scope domain scanned; findings recorded with severity + confidence. If fails → re-read progress checklist + `ds/audit/findings.md`; resume from first incomplete; if a domain still fails after retry (file unreadable, context lost) → mark `partial` in `state.data.scopes_done` with collected findings, continue.

### Phase 5: Report

#### Standard Report (audit modes)

```
## Audit Report — {project-name}
Platform: {platform} | Scanned: {domains} | Date: {today}
Architecture: {summary}

### Conformance Issues (CAT-1)
| # | Rule | Sev | File:Line | Issue | Impact | Fix | Conf |

### Enhancement Opportunities (CAT-2) — pre-approved
| # | Rule | Sev | File:Line | Issue | Impact | Fix | Conf |

### Potential Issues (LOW confidence)
| # | Rule | File:Line | Issue | Suggested Fix |

### Summary
| Category | CRITICAL | HIGH | MEDIUM | LOW | Total |
```

**Severity:** CRITICAL > HIGH > MEDIUM > LOW. Uncertain → choose lower.

#### Release Readiness Report (release-ready mode)

Per references/scoring.md: 100-point dynamic scoring across 7 dimensions, manual gates, consequence table, diff against previous report.

Include: policy values used (fetched vs fallback), dimension breakdown with bar chart, findings by severity, manual gate status, and "if you publish now" consequence table for CRITICAL+HIGH.

**Gate:** Report with findings + severities + summary. If fails → domain produced no findings due to scan error (not because it was clean) → re-run scan once; still fails → present report with failed domains marked "scan incomplete", findings count `?` in summary.

### Phase 6: Post-Report

| Mode | Behavior |
|------|----------|
| `audit` | Ask: Fix all / CRITICAL+HIGH only / Pick by severity / Report only |
| `audit+fix` | Auto-transition to fix |
| `quick-fix` | Auto-apply all |
| `release-ready` | Ask: Fix plan / Save report only / Guidance for key findings |

**Gate:** User selected post-report action; mode-specific next step determined. If fails → no selection after one re-prompt → mode default: `audit` → Report only; `audit+fix` → Fix all; `quick-fix` → Auto-apply all; `release-ready` → Save report only. Record default in `state.data.fix_progress`.

### Phase 7: Fix [SKIP if audit-only or report-only]

1. **Plan.** Read findings, apply severity filter, group by file, identify dependencies. Present CAT-1 + CAT-2 (pre-approved).
2. **Confirmation:** `quick-fix` → summary + proceed; `audit+fix` → full plan + ask; `release-ready` → show auto-fixable vs guidance split.
3. **Execute.** Apply grouped by file. Re-read before + after each edit. Record applied/failed/skipped.

**Gate:** All standard fixes attempted; each recorded. If fails → fix unattempt-able (file unreadable, edit error) → record `failed` in `state.data.findings[].disposition`, revert any partial edit via re-read + restore, continue; list failed fixes in Phase 9 summary with reason.

### Phase 8: Needs-Approval Review [needs_approval > 0]

`--auto`: list and skip. `--force-approve`: apply all. **Interactive:** present with risk context, ask Apply All / Review Each / Skip All. `approve-all` excludes CRITICAL.

**Gate:** All items resolved (applied → fixed/failed, declined → skipped). If fails → unresolved → record `pending-user-decision` in `state.data.findings[].disposition`, proceed to Summary with status WARN, list unresolved items prominently.

### Phase 9: Summary

```
ds-mobile: {OK|WARN|FAIL} | Mode: {audit|audit+fix|quick-fix|release-ready} | Fixed: {n} | Skipped: {n} | Failed: {n} | Total: {n}
```

**Cleanup:** remove mobile-scoped findings (security, privacy, regulatory, store, ux, visual, a11y, arch, testing, perf, network, i18n, release) from `ds/audit/findings.md`. Empty after removal → delete file.

FRC+DSC accounting.

**Gate:** `fixed + failed + skipped + needs_approval + not_applicable = total`; every modified file re-read; mobile-scoped findings removed from `ds/audit/findings.md`. If fails → counts unreconciled → identify undisposed finding, assign `failed` reason "disposition not recorded", re-run count; cleanup fails → warn, leave file intact rather than partial-modify.

**Value Delivered:** 1-5 concrete mobile-quality outcomes. Example shapes (placeholders, not literal):

- `{n} store-rejection risks intercepted (permission abuse, missing privacy declarations, undocumented background tasks) — submission round-trip saved`
- `{n} CRITICAL findings: hardcoded API keys / unencrypted PII in shared preferences — exposure window before next release closed`
- `{n} mobile a11y findings (small touch targets, missing semantic labels, contrast on dark mode) — accessibility lawsuit + EAA compliance risk reduced`
- `Release-readiness score: {before} → {after} / 100 — go/no-go decision is now measurable, not vibes`

Audit-only run: `{n} findings (severity: {breakdown}) — actionable list returned, no source modified`.

## Quality Gates

1. **No cascading breakage** — verify no broken imports/references after fixes; fix breaks another file → revert, mark failed, continue
2. **Format preservation** — match existing indentation + code style
3. **Scope boundary** — only touch lines task requires
4. **Platform consistency** — fixes use correct platform API
5. **Artifact-first recovery** — re-read files before + after editing
6. **FRC** — every finding gets a disposition in summary
7. W1: cite file:line, never assume. W2: check consumers after modify. W3: only task-required lines. W4: re-read after gap. W5: uncertain → lower severity. W6: verify all phases output. W7: dedup file:line. W8: no raw shell interpolation. W9: `ds/audit/mobile.json` updated per scope, gitignored, deleted on successful Summary. W10: defer detection to fresh `ds/audit/findings.md` — own scan only for uncovered scopes. W11: every detected error gets a concrete disposition — pre-existing/out-of-scope is not a valid skip reason.

## Edge Cases

| Scenario | Behavior |
|----------|----------|
| No project file found | Stop: "Mobile project not found in current directory." |
| Platform ambiguous | Ask user to confirm |
| Reference file fails to load | Skip domain, note as N/A |
| Architecture Discovery: no corrections | Use detected values |
| CAT-2 list: user selects 'none' | Audit CAT-1 rules only (default) |
| Zero findings in domain | Report domain as clean |
| Fix: file changed externally | Re-read before each edit |
| Fix: edit fails | Skip, log as failed, continue |
| Regulatory: no active frameworks | Skip PRV-06–18 regulatory rules |
| Release-ready: policy fetch fails | Use fallback values, warn in report |
| Release-ready: first run | No previous `ds/mobile/release.json` → no diff, note "First audit" |
| Release-ready: corrupt JSON report | Warn, treat as first audit (skip diff), overwrite |
