# Offline subscription discovery from fictional emails

This is a real, reproducible script run over **12 author-created emails from eight fictional merchants**. It did not access anyone's inbox, contact a merchant, send an email, make a payment, or cancel anything. All merchant domains end in `.example`. The fixed audit date is **September 17, 2026**.

Run with Python 3.9 or newer; no packages are required:

```sh
python3 audit-subscriptions.py
```

Keep the files in the same directory. The script reads `sample-emails.json`, performs its fixture assertions, and writes `subscription-report.json` and `subscription-report.csv`. The JSON includes email IDs and exact body excerpts supporting each row. Running it again produces the same report bytes.

Included files:

- `sample-emails.json`: the original fictional plaintext messages, with dates, IDs, senders, subjects, and bodies.
- `audit-subscriptions.py`: a dependency-free reference parser and its checks.
- `subscription-report.json`: actual generated report, evidence, deduplication decisions, and limitations.
- `subscription-report.csv`: the generated flat report for a spreadsheet.
- `README.md`: instructions and scope.

The parser extracts values from explicit labeled email-body fields such as `Invoice ID:`, `Amount charged:`, and `Billing cadence:`. It does not look up a prewritten classification for a merchant. A sender domain is a grouping label in this fixture, not authentication or proof that a bill is legitimate. This controlled format makes the result inspectable, but it does **not** demonstrate general extraction accuracy on real-world email or constitute a production AI benchmark.

The twelve messages comprise eight distinct paid invoices, one duplicate receipt, one cancellation notice, one refund notice, and one trial notice. Paperplane has two genuinely different monthly invoices and a duplicate copy of its September invoice. Only the duplicate is excluded; the recurring-rate estimate uses the latest unique invoice's rate once, rather than adding historical invoices together.

The report deliberately says `paid_candidate`, never confirmed active. Its other statuses are `cancellation_notice`, `trial`, `needs_review`, and `one_off`. Cancellation and refund notices are matched to a known invoice within the same fictional merchant. A cancellation notice that explicitly disables renewal overrides the earlier receipt's next-charge date. A matching refund instead triggers review: it does not establish cancellation. An unknown cadence also triggers review.

Only the three paid candidates enter the normalized rate comparison: **USD 22.00 per month equivalent**, and **EUR 9.00 per month**, kept separate. The USD number is Paperplane's USD 12 monthly rate plus Archivebox's USD 120 annual rate divided by twelve. Archivebox's **USD 10 monthly equivalent is not an actual monthly payment**. These totals are neither this month's cash flow, an amount already spent, nor a prediction of confirmed upcoming charges. There is no FX conversion or combined currency total.

The canceled subscription, refunded-invoice review case, one-off purchase, unpaid trial, and unknown-cadence receipt are excluded from those totals. Trydesk's advertised future USD 18 monthly price is retained as evidence but is not mistaken for an actual paid subscription or scheduled charge.

This script handles only its controlled fixture labels. It does not support arbitrary natural language, HTML/MIME, attachments, OCR, aliases, app-store bundles, tax, proration, discounts, or live account verification. It cannot establish that every subscription has been found. In a real audit, review the evidence and verify uncertain renewal settings in the merchant account before deciding what to keep or cancel.
