# Tenant Cleanup — Canonical Tenants + Junk Removal (PLAN/MEMORY)

**Created**: 2026-06-04 · **Status**: PARTIAL — work is scoped to the real Pascucci tenant (done);
the mass deletion of junk tenants is **planned, NOT yet executed** (needs its own careful run — see below).

---

## CANONICAL TENANTS (the only 5 that should exist)

Per Luca, Finanly has exactly **5 real tenants**. Keep these; everything else is test junk.

| Tenant name | Tenant ID | ERPNext? |
|---|---|---|
| **Pascucci USA** | `837eebaa-1ae8-5b79-95c3-26649fb25c42` | ✅ real creds (the one our ad-receipt work uses) |
| Nourishing | `9f26992c-66ab-5d16-af1f-b9ae98f40021` | ✅ |
| Fine Line | `5bd249c8-99b0-5343-a112-31aeae1c4f3a` | ✅ |
| Ad Astrum | `2328ddfa-f48d-5213-872b-aa07a3b1db01` | ✅ |
| Luca Capula | `459d947f-c556-46b6-a6e5-64bebbfcd4f2` | personal (no ERPNext) |

> **THE REAL PASCUCCI TENANT IS `837eebaa-1ae8-5b79-95c3-26649fb25c42`.** All Meta/Google ad-receipt
> work, the intercompany DBA invoices, and every books edit this session target **Pascucci's ERPNext
> company `Pascucci USA Inc`** — never any other tenant. Do not confuse it with the parity copies.

## JUNK TO DELETE (82 tenants — test/seed fixtures, NOT real)

As of 2026-06-04 the `tenants` table had **87** rows. The 82 non-canonical:

| Name | Count | Notes |
|---|---|---|
| `Parity Tenant` | 56 | seeded for parity tests; 28 of them claim company `Pascucci USA Inc` but have **no secret-broker creds** |
| `T` | 25 | single-letter test tenants |
| `Simone` | 1 | not in the canonical 5 |

## WHY OUR WORK IS ALREADY SAFE (no tenant confusion)

1. **Backfill scripts** (`temp/meta_receipts/*`, `temp/google_invoices/*`, `temp/intercompany_mirror/*`)
   talk to **ERPNext directly** using `ERP_BASE_URL/ERP_API_KEY/ERP_API_SECRET` from `infra/docker/.env`,
   scoped by `company = "Pascucci USA Inc"`. They have **no finanly-tenant dimension** — they only ever
   touched Pascucci's books. No parity/test tenant is reachable from them.
2. **Hourly Meta ingest** (`finanly_jobs.tasks.meta_ad_receipts_ingest_all_tenants`) loops every active
   tenant whose ERPNext integration is bound to `Pascucci USA Inc` (29 today: 1 real + 28 parity). It is
   now **credential-gated**: on the first `core_api_secret_broker_error` for a target it **skips the whole
   target**. Only the credentialed real Pascucci tenant (`837eebaa…`) actually creates/dedups PIs.
   Verified live: `created=0, skipped_existing=13, skipped_targets_no_credentials=28, failures=0`.

## DELETING THE JUNK TENANTS — why it's a separate, careful job

`tenants` has **72 foreign keys pointing at it, ALL `ON DELETE NO ACTION`** (zero CASCADE). So a plain
`DELETE FROM tenants WHERE …` will be **blocked** by any child row in any of 72 tables
(integration_instances, canonical_transactions, audit_events, personal_*, ledger_*, shopify_*, ga4_*,
shipments, …). Safe deletion requires either:
- **(A) Recommended**: delete child rows tenant-by-tenant across all 72 referencing tables in FK order,
  inside one transaction per tenant, then delete the tenant row. Build a script that:
  1. enumerates the 72 referencing tables from `pg_constraint` (don't hardcode),
  2. for each junk tenant id, `DELETE` from each child table `where tenant_id = :tid` (respect RLS /
     `_set_tenant`), then `DELETE FROM tenants`,
  3. asserts the 5 canonical ids are untouched (count before/after).
- **(B) Soft option**: set the 82 junk tenants `status='inactive'` (one UPDATE). Non-destructive, removes
  them from all `status='active'` scans (incl. the Meta job) immediately. Reversible. Lower risk; leaves
  rows in place.

**NOT done yet** — needs explicit go + a dedicated script with a dry-run + a keep-list guard on the 5
canonical ids. Until then, the credential-gating above already prevents any junk tenant from affecting
real books.

## Keep-list guard (use in any deletion script)
```
KEEP = {
  "837eebaa-1ae8-5b79-95c3-26649fb25c42",  # Pascucci USA  (REAL Pascucci)
  "9f26992c-66ab-5d16-af1f-b9ae98f40021",  # Nourishing
  "5bd249c8-99b0-5343-a112-31aeae1c4f3a",  # Fine Line
  "2328ddfa-f48d-5213-872b-aa07a3b1db01",  # Ad Astrum
  "459d947f-c556-46b6-a6e5-64bebbfcd4f2",  # Luca Capula
}
# delete ONLY tenants whose id not in KEEP. Abort if the post-delete count != 5.
```
