Appearance
Discrepancies
The System → Discrepancies page is the triage inbox for tenant-level dangling data. The audit worker periodically scans every instance and surfaces records that exist in one data store but not the other:
- Ghost — a PostgreSQL row with no MongoDB data.
- Orphan — MongoDB data with no PostgreSQL row.
The ideal state is zero discrepancies. Anything in this inbox needs attention.
Layout
- Header with title and a Run scan button (top right).
- Toolbar with three filters and a Clear button.
- Table with infinite scroll.
Toolbar
| Control | Behaviour |
|---|---|
| Status | Open / Resolved / Discarded / Auto-purged. Defaults to Open. |
| Kind | Ghost / Orphan. Optional. |
| Instance | Filter by instance. Optional. |
| Clear | Resets all filters to defaults. |
| Run scan | Triggers a new audit cycle immediately. |
| Count | "N matching". |
Columns
| Column | Notes |
|---|---|
| Kind | Ghost (danger) / Orphan (warning) badge. |
| Instance | Affected instance. |
| Tenant name | Tenant display name, when known. |
| Tenant code | Monospace identifier. |
| First seen | When the discrepancy was first detected. |
| Last seen | When the most recent scan still detected it. |
| Status | Open / Resolved / Discarded / Auto-purged. |
| Evidence | Link button with a teaser ("3 coll · customer doc" for orphans; "last job" for ghosts). |
| Actions | Trash (purge) and X (discard) for open rows; resolution note for closed rows. |
A row's background tints red if status is overdue.
Evidence modal
Click the evidence link to see the audit signals that triggered the finding:
- Orphans — matched MongoDB collections, whether the tenant ID had whitespace or case variants.
- Ghosts — PG tenant ID, creation date, last job timestamp.
This is what you read before deciding to purge.
Actions on a finding
| Action | What it does |
|---|---|
| Purge (trash) | Deletes the dangling record. Ghost purges run inline. Orphan purges enqueue a job and offer a "View job" link to track on Migrations. Requires confirmation. |
| Discard (X) | Marks the row as discarded and hides it from the inbox. Not permanent — the next audit scan re-detects and flips back to open if the dangle still exists. Discard means "snooze until next audit cycle." |
There is no manual "Resolve" — that happens automatically when the next audit scan no longer detects the finding. The note no longer detected is recorded.
Lifecycle
open ──┬──▶ resolved (purged or fixed elsewhere)
├──▶ discarded (snoozed; may flip back to open on next scan)
└──▶ auto_purged (worker met strict criteria and acted without you)The auto-purge path is conservative — strict age and inactivity thresholds must be met. Most findings need a human in the loop.
Notes
- Each dangle is keyed by
(instance, tenant code, kind). The same finding across scans is one row, not many. - Discard is for "I've looked at this and don't want to act yet." It is not "ignore forever." If you genuinely never want to see it again, fix the root cause so the next scan finds nothing.
- The page lists only tenant discrepancies. Future non-tenant finding domains (billing reconciliation, security audit, data integrity) get their own pages — they have different keying and different rules.

