Owner Nikunj

Compliance Gap Memo — Asym (Internal)

Compliance Gap Memo — Asym (Internal)

Date: 2026-07-03 Scope: Asym app (Android com.app.stema in stema repo; iOS com.asymmetriclabs.upsc in stema-ios repo; backend keystone). Purpose: Product/engineering changes required so that reality matches the published Terms & Privacy Policy and store policies. The legal documents describe the intended-compliant state; items below are what must actually change. Ordered blocker → advisory.


BLOCKERS (store rejection / policy violation risk)

1. Android has no account-deletion flow — Google Play requirement

  • iOS has delete (AuthManager.deleteUser()DELETE users); Android offers only Logout (feature/settings/profile/AccountDetailsScreen.kt, no @DELETE in ApiService.kt).
  • Google Play requires both an in-app deletion path and a web deletion URL (entered in Play Console Data safety) for any app with account creation.
  • Fix: add delete-account to Android settings (backend endpoint already exists), and stand up a web deletion page/request URL (e.g., asymmetriclabs.ai/delete-account).
  • Also verify the delete button is actually reachable in iOS UI2 profile (confirmed in UI1 only).

2. Razorpay checkout inside the apps for digital subscriptions

  • Android integrates Razorpay checkout in-app (com.razorpay:checkout in app/build.gradle.kts:207, plans/paywall in feature/settings/plans/). Google Play’s Payments policy requires Play Billing for in-app digital goods → rejection/removal risk.
  • iOS currently only reads subscription status (no purchase UI, no StoreKit) — closer to a “reader”-style posture, but any in-app purchase flow or hard-sell upgrade link will trip Apple 3.1.1/3.1.3.
  • Decision needed (business): (a) adopt Play Billing / Apple IAP for in-app purchases; (b) remove purchase flows from the apps entirely and sell only on the web (with the apps not linking out on iOS unless using an approved entitlement); or (c) qualify for an alternative-billing program where available.
  • T&C §5.3 is written platform-agnostically so it survives any of these outcomes.
  • Policy commits to consent-based processing and a 16+ floor with guardian consent for under-18s. No age gate, consent checkbox, or guardian attestation exists anywhere (backend date_of_birth optional and unenforced).
  • Fix: at signup — (a) unticked consent affirmation linking Terms + Privacy Policy (record timestamp + policy version against the user); (b) age confirmation (16+); (c) if 16–17, guardian-consent attestation flow. Keep consent records auditable; DPDP Rules will require notice-per-consent and easy withdrawal.

HIGH

4. UGC (comments) lacks report / block / moderation — Apple Guideline 1.2

  • Users can post/reply/delete comments (iOS CommentRepository.swift; backend comment_models), but there is no report-comment, block-user, or content filter. Apple requires: filtering objectionable material, a reporting mechanism, ability to block abusive users, and published contact info.
  • Backend has POST users/report for content issues — extend it (or add an endpoint) for reporting comments/users, plus admin takedown tooling. T&C §7.3 already promises a reporting mechanism.

5. Missing app-level PrivacyInfo.xcprivacy (iOS)

  • No app-authored privacy manifest anywhere in Asym/, Docket/, Hela/, or Packages/. The app uses required-reason APIs (Keychain, UserDefaults, file timestamps, identifierForVendor, boot-time via SDKs).
  • Fix: add a privacy manifest declaring collected data types (matching the Privacy Policy §1) and required-reason API usage. Also confirm whether GoogleAppMeasurement / google-ads-on-device-conversion end up in the linked binary (they’re in the resolved SPM graph) — affects the App Store privacy label (“Data used to track you” must stay empty).

6. AD_ID permission + silent Firebase Analytics (Android)

  • firebase-analytics is included with no explicit logEvent calls — automatic collection is on, and com.google.android.gms.permission.AD_ID auto-merges on targetSdk 33+.
  • The Privacy Policy states no ad tracking. Fix (pick one): remove firebase-analytics (Crashlytics/Messaging don’t need it); or keep it but add <uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove"/>, disable ad-ID collection, and declare “App interactions” analytics in Data safety.
  • Ensure Play Console Data safety answers mirror Privacy Policy §1 exactly (email, phone, name, device IDs, IP/approx-location, usage, crash data; sharing with the processors listed).

7. Login/IP/location logs retained indefinitely

  • Privacy Policy §6 commits to 90 days. The 90-day TTL index on login_activities is commented out (keystone src/models/login_activity_models/db_model.py:120-125), and login_attempt_log has no TTL either.
  • Fix: re-enable the TTL index (and add one for login_attempt_log) before the policy goes live, or the published retention statement is false.

MEDIUM

8. No data-access/export path (DPDP §11)

  • Policy §8 grants access/summary rights; no endpoint or process exists.
  • Fix: minimum viable — documented manual process behind legal@asymmetriclabs.ai (verify identity, compile summary). Later: self-serve export endpoint.

9. Cleartext http://ip-api.com call

  • Android: AppModule.kt:145-154 uses http:// — blocked by default on targetSdk 36 release builds (feature will silently break). iOS: ATS exception for ip-api.com in Info.plist.
  • Sends every user’s IP to a third party over plaintext; ip-api.com’s free tier also prohibits commercial use.
  • Fix: switch to HTTPS on a paid/commercial geo-IP plan, do the lookup server-side (backend already calls ip-api from ip_api_services.py — client call may be redundant), or drop client-side geo entirely. Remove the ATS exception.

10. AI feature logging vs. policy promise

  • Policy §4 states AI providers don’t train on user queries. Verify the OpenAI/Anthropic/Google/ElevenLabs/Sarvam accounts are on API/enterprise terms with training opt-out (default for OpenAI/Anthropic APIs; confirm Gemini tier and Sarvam terms). Also implement the stated 12-month TTL on ai_search_query_logs.

LOW / CLEANUP

  • Docs will live at asymmetriclabs.ai/terms + /privacy, but apps link elsewhere: iOS ConfigurationManager.swift:181-183parixa.cybosapiens.com/{terms,privacy}; Android AppConstants.kt:14-29web1-parixa.asymmetriclabs.ai/{terms,privacy}.
  • Fix: serve the final documents at every URL the shipped apps reference (redirects are fine), and update constants to the canonical URLs in the next release. App Store Connect + Play Console listings must use the canonical privacy URL.

12. Housekeeping

  • Remove ngrok associated domain from Asym.entitlements before release.
  • Replace personal emails in backend config (abhiigatty@…, personal Gmails in app_config.py:33,44) with role addresses.
  • iOS UI2 App Store ID placeholder "0000000000" (ProfileSeams.swift:42); Docket Google OAuth placeholders.
  • mailto:legal@asymmetriclabs.com (wrong TLD — should be .ai) in iOS APIBlockView.swift:88.
  • Invoice generation is a stub (keystone src/services/invoice_service.py) — GST-compliant invoices are expected for paid plans; policy/T&C reference receipts.
  • Hardcoded Slack webhook in keystone app_config.py:40 — move to env/secret manager.

Store-submission checklist (once blockers are fixed)

  • Privacy Policy + Terms live at asymmetriclabs.ai/privacy and /terms (and legacy URLs redirect)
  • Play Console: Data safety form matches Privacy Policy §1/§3; account-deletion URL set; target-audience = 16+/adults (not Families)
  • App Store Connect: privacy nutrition labels match Privacy Policy §1 (Contact Info, Identifiers, Usage Data, Diagnostics, Coarse Location; no Tracking); privacy-policy URL set; age rating reflects UGC
  • In-app signup shows consent checkbox + links to both documents (already partially present on Android login screen)
  • Account deletion works in-app on both platforms + web URL
  • Effective dates and registered-office address filled in both documents

Note: This memo and the drafted documents are working drafts prepared from a code audit. Have them reviewed by qualified Indian counsel before publication — particularly the refund terms (§5.7), the liability cap (§11.2), and DPDP children’s-consent mechanics, which the DPDP Rules may further specify.