Ship gate
What a change must pass before deploy
Use this as the last step of any PR or deploy on an RM app. It is written so an AI agent can self-check and print the answers. "N/A" is an acceptable answer only with a one-line reason.
The 60-second gate (every change)#
- Data: Did this change add, move, or expose any personal-data field? If yes, is it in the app's data map with class, purpose, retention, and processor? Is a P0 field involved? If P0, is there explicit consent, encryption at rest, access logging, and exclusion from analytics and prompts?
- Claims: Did any user-facing text change? Does every claim remain literally true of the code (encryption, privacy, accuracy, uptime, customers, results)? No em-dashes, no emoji, no fake urgency, no invented numbers.
- AI: Does this change call a model? Is the provider on the app's approved list (local by default)? Is AI disclosed where the output appears? Is a human approval step present for consequential outputs? Are outputs treated as untrusted input? Are prompts in the repo with tests?
- Auth and tenancy: Is every new endpoint authenticated and authorised server-side, scoped to the tenant, rate-limited, and free of state-changing GETs? Any new id in a URL checked against ownership?
- Secrets: Nothing new in git?
.envmode 600? Rotation path known? - Comms: Does this change send email, SMS, push, or WhatsApp? Transactional or marketing? Consent checked? Suppression list honoured? Unsubscribe present? Sender is rmmail.in through Resend? Quota cap and fallback?
- Money: Does this change touch prices, tax, invoices, subscriptions, or third-party funds? Tax treatment shown? Cancellation as easy as signup? Funds of others only through Connect or Route? Numbered documents untouched?
- Content: Does this change accept uploads or publish user content? Type sniffing, size caps, scanning, takedown path, retention?
- Region: Does behaviour depend on the user's region where the law does (consent UX, cancellation rights, tax, disclaimers, breach tags)? Unknown region defaults to the strict path?
- Accessibility: Keyboard, labels, contrast, focus, error messages; nothing only reachable through a script that can fail.
- Logs: No PII, tokens, message bodies, or health data in logs; 180-day retention still true.
- Tests: Regression tests exist for any compliance-critical behaviour this change touches (consent gating, tenant isolation, redaction, guardrails, tax math, suppression).
Change-triggered deep checks#
| If the change... | Then also run... |
|---|---|
| Adds a third-party service (SDK, API, relay, LLM) | Vendor register entry, DPA signed, no-training and retention settings chosen, sub-processor page updated, 30-day customer notice for business products |
| Adds a cloud LLM call to a local-only app | Stop. Needs an explicit exception in the app register and a copy change in the privacy notice and /legal/ai |
| Adds health, children's, immigration, biometric, location, or financial fields | P0 procedure: consent screen, DPIA entry, encryption, retention, rights, breach-clock tags; domain module review |
| Adds recording, transcription, or screen capture | Consent prompt, indicator, region-aware two-party handling, retention default, access inheritance |
| Adds a public page or share link | Trust pages linked, security headers, rate limits, scanning, expiry defaults, robots and indexing decisions |
| Adds a pricing or plan change | Pre-purchase disclosure screen, renewal reminders, cancellation path, receipts, tax lines, store billing rules if in an app |
| Adds a scheduled job that sends anything | Per-tenant scoping, daily budget, suppression, dry-run mode, kill switch |
| Adds scraping or automation against a third-party site | Stop. Terms review and written risk acceptance in the app register first |
| Adds a new login or identity path | NIST 800-63B checklist, MFA preserved, recovery does not bypass MFA, session revocation |
| Adds a new tenant, org, or client concept | Row-level isolation test, cross-tenant negative tests, admin scoping |
| Changes a legal page | Version and date bump, consent re-capture if material, archive of the old version |
| Moves data to a new host or region | Transfer tool check (IDTA, SCCs), notice update, CERT-In log location still India |
| Touches invoices, tax, or accounting | Denominator and total tests, state code and place-of-supply tests, immutability preserved |
| Adds generated images, audio, or video | Visible AI label, provenance metadata where supported, likeness and voice consent |
| Adds a feature minors could use | Age gate, no profiling or ads, parental consent for India under-18, COPPA for US under-13 |
Release checklist for a first public launch of an app#
- Data map complete; DPIA done if any P0 data.
- Trust pages live: privacy, terms, cookies (UK and EU), refunds (if charging), sub-processors, DPA (business), grievance officer (India), AI page, accessibility statement, security page with security.txt, DMCA page (uploads), retention schedule.
- Region handling and age gate in signup.
- Consent ledger writing.
- Rights portal: export, correct, delete, withdraw, complain.
- MFA available; admin MFA enforced; rate limits; security headers; CSP.
- Backups encrypted, off-box, restore tested and logged.
- Logging 180 days in India, redaction tested.
- Incident runbook contacts filled for this app.
- Sending domain authenticated; suppression list wired; send caps set.
- Payments through hosted fields; webhooks verified; tax lines right; cancellation path tested.
- App store forms (if mobile) match the code.
- Copy review: no banned claims, no em-dashes, no invented numbers, correct operator identity.
- Accessibility pass with keyboard and a screen reader.
- A named human owner for compliance questions on this app.
Launch controls: evidence, not a yes#
The checklist above can be ticked from memory, and on CampusIndex (2026-10-11) it was. That app had every item "covered" while its privacy page claimed an audited access trail that did not exist, it promised a WhatsApp opt-out with no switch, it collected consent with no record, and it handed children their own logins. A reel listing six US laws (COPPA, Google Fonts/GDPR, CIPA session replay, CAN-SPAM, auto-renewal, DMCA agent) found it, not the gate. None of those six laws applied to an India-only app. Their Indian equivalents did, and none had a test.
So every control below needs a piece of evidence: a test name, a command and its output, or a live URL. "Yes" is not an answer. A control with no evidence is open.
| # | Control | Evidence that counts |
|---|---|---|
| L1 | Nothing loads from another website (fonts, CDNs, analytics, images, embeds) unless it is a listed sub-processor | A CSP header with default-src 'self', plus a Playwright crawl of public and per-role pages reporting 0 outside requests (CampusIndex: scripts/third_party_scan.py) |
| L2 | No session replay, heatmaps or behavioural analytics on pages children or patients use; elsewhere off by default and disclosed | The same crawl, plus a grep of the bundle for the vendor SDKs |
| L3 | Age and consent: who may sign up, and the parental-consent record for minors (DPDP s.9 and Rule 10, from 13 May 2027; COPPA if US) | A test that a minor's account is refused or gated, and a test that consent is stored with the exact notice text, version, method and withdrawal |
| L4 | Grievance and takedown: a named Grievance Officer published (IT Rules 2021 r.3(2), DPDP s.13), a complaint form, acknowledgement within 24h, resolution clocks (36h for unlawful content, 7 days otherwise), a DMCA agent if serving the US with uploads | The live contact endpoint or page, and a test that a complaint gets a reference and a due time |
| L5 | Every claim on a legal page is a test: "audited", "encrypted", "opt out", "we never share", "data stays in India" | One test per claim, named after the sentence (CampusIndex: tests/test_launch_controls.py). A claim with no test is removed or rewritten. |
| L6 | Sub-processors listed match the code: every outbound host in the code is on the sub-processor page and the DPA annex | A grep of outbound hosts compared with the published list |
| L7 | Messages: marketing has an unsubscribe link and a postal address (CAN-SPAM if US); SMS uses the right TRAI DLT category; WhatsApp and SMS can be turned off and the switch is honoured at send time | A test that an opted-out user is not sent on that channel |
| L8 | Recurring payments: renewal price, interval and how to cancel sit next to the pay button; RBI e-mandate rules (pre-debit notice, AFA above the limit); auto-renewal law if US/CA | A screenshot of the checkout, plus a test or log of the pre-debit notice |
| L9 | Access trail: reads of sensitive records and all changes are logged with who, what and when, kept at least a year (DPDP Rules, Rule 6), and readable by the customer's admin | A test that a sensitive read writes an audit row |
| L10 | Log hygiene: no phone numbers, message bodies, tokens or health data in logs; rotation set | A grep of a day's container logs for 10-digit numbers and known message phrases |
| L11 | User-supplied URLs (avatars, logos, product images) are uploads, not links; an outside URL is a tracking pixel | A validator test that refuses https:// and // image URLs |
| L12 | Nothing for testing ships to production: no demo or default credentials in the bundle or the schema, no public API reference, no placeholder contact details | A grep of the built pages for known test passwords and placeholder numbers (CampusIndex: test_public_pages_say_nothing_the_product_cannot_do), and /docs answering 404 |
| L13 | Every list endpoint is scoped for the least-privileged role that can call it | A test that signs in as that role (a parent) and calls each list route (CampusIndex found GET /students open to parents on 2026-10-12) |
| L14 | Rights are complete, not partial: "export everything" walks every table that holds the person; erasure names what it keeps and why | A test that creates a record in a side table, exports and erases, and checks both |
| L15 | A full read by someone who did not write it, before the first real user: security, flows and claims-against-code, each as its own pass | The three reports, and a test for every finding closed |
Rerun on every launch and every quarter. The laws move: the IT Rules were amended in 2026, and DPDP's children's duties start 13 May 2027. 08-open-questions.md holds what counsel still has to confirm.
How an AI agent should report the gate#
Print a short block at the end of the task:
COMPLIANCE GATE
data: no new personal fields | added: <field> (P1) documented in docs/DATA_MAP.md
claims: unchanged | changed: <where>, verified true
ai: none | local ollama, disclosed in <component>, human approval at <step>
auth: n/a | new endpoint <path> authz tested in <test>
comms: none | transactional email via Resend, suppression honoured
money: n/a
content: n/a
region: n/a | consent layer varies by region in <component>
tests: <list>
launch controls: n/a (not a launch) | L1-L11 each with its evidence, or listed under open
open: <anything needing a human>