# Stale contacts queued for re-verification, not deleted

- **Pattern:** `ab-000867` (`data-quality-list-hygiene.data-decay.stale-queue-not-delete`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000867
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000867)

## Why it matters

Hard-deleting stale contacts destroys their suppression history. If the same email address reappears in a future import, the system treats it as a net-new contact with no prior history — re-adding it to the active list even if the person previously bounced or unsubscribed. This directly violates CAN-SPAM § 5's requirement to honor unsubscribes permanently (suppression history is the evidence of compliance). Under GDPR Art. 17, the right to erasure is separate from list removal: even when personal data is erased, a suppression record (email hash or similar) must be retained to prevent the address from being re-added in future imports.

## Severity rationale

Low because hard-deletion of stale contacts typically removes a small fraction of the list at a time, but each deletion permanently destroys the suppression evidence needed for regulatory compliance.

## Remediation

Replace hard DELETE cleanup paths with status transitions that preserve the contact record and its suppression history:

```sql
-- Add status column if absent:
ALTER TABLE contacts ADD COLUMN status TEXT NOT NULL DEFAULT 'active'
  CHECK (status IN ('active', 'at_risk', 'inactive', 'lapsed', 'suppressed', 'pending_reverification'));

-- Stale cleanup: transition, never delete:
UPDATE contacts
SET status = 'pending_reverification'
WHERE last_engaged_at < now() - interval '180 days'
  AND status = 'inactive';
```

For GDPR Art. 17 erasure requests where personal data must be deleted, retain a suppression shadow: after erasing the contact record, insert a row in a `suppression_list` table with the email (or a hash) and reason `gdpr_erasure`. This prevents re-import of erased addresses without retaining PII beyond what is needed.

## Detection

- **ID:** `stale-queue-not-delete`
- **Severity:** `low`
- **What to look for:** Count all code paths that handle stale contacts and classify each as "soft-delete" or "hard-delete." Check what happens when a contact is identified as stale. The correct pattern is to queue them for re-verification or move them to a suppressed segment — not to delete them immediately. Deletion destroys suppression history and can cause the same address to reappear as "new" in a future import. Look for soft-delete patterns (`deleted_at IS NULL`) or a status transition to a `pending_reverification` state rather than a hard DELETE.
- **Pass criteria:** Stale contacts are moved to a quarantine or re-verification segment with at least 1 soft-delete or status-transition path. No more than 0 stale-handling code paths use hard DELETE. Suppression history is preserved regardless of contact status.
- **Fail criteria:** Stale contacts are hard-deleted from the database via at least 1 code path, wiping their suppression history.
- **Skip (N/A) when:** Suppression is managed in a separate system (e.g., the ESP's global suppression list) that is not affected by contact record deletion.
- **Detail on fail:** Example: `"Stale contact cleanup job runs DELETE FROM contacts WHERE last_engaged_at < ... — suppression history destroyed on cleanup"`
- **Remediation:** Use soft-delete with status transitions:

  ```sql
  -- Add status column if not present:
  ALTER TABLE contacts ADD COLUMN status TEXT NOT NULL DEFAULT 'active'
    CHECK (status IN ('active', 'at_risk', 'inactive', 'lapsed', 'suppressed', 'pending_reverification'));

  -- Stale cleanup: transition status, never hard-delete
  UPDATE contacts
  SET status = 'pending_reverification'
  WHERE last_engaged_at < now() - interval '180 days'
    AND status = 'inactive';
  ```

  If compliance requirements (GDPR right to erasure) require deletion, maintain a separate `suppression_list` table for suppressed emails that persists even after the contact record is erased.

## External references

- gdpr Art. 17
- iso-25010 functional-correctness

Taxons: data-integrity, privacy-consent

HTML version: https://auditbuffet.com/patterns/ab-000867
