# Missing or stuck chart reviews

**Symptom:** a customer says reviews didn't run, a run sits in progress forever, or someone notices "very few triggered reviews" in the logs.

## First: is it actually missing?

Count from `audit_runs`, not from log lines. The submission log goes through the Vercel log drain with no flush, so under load most lines are dropped. A 2026-06 "almost no triggered reviews" alarm was ~4 log lines against ~475 successful traces.

- `audit_runs` with `trigger is not null` for triggered reviews. There is no `entity_id`; join `cases → patient` to scope to an org.
- Datadog APM traces for `RunTriggeredChartReviewJobbable` / `RunChartReviewJobbable`.
- Some integrations still run on v1. Their reviews won't appear in v2 tables at all.

If `audit_runs` and traces agree volume is normal, it's an observability artifact. Stop there.

## Stuck in `running`

- Older than the stale window (60 min): the cleanup cron will flip it to `failed` within 5 minutes. Then requeue it from Superadmin → Audit runs.
- A 504 kills a job without writing `failed`. If many are stuck at once, check for a [queue storm](./queue-storm.md) first.

## Failed with zero responses

Usually a **dedup orphan**: the triggered-review service creates the `audit_runs` row before `performLater` checks `job_executions`. If an unexpired row exists for the trigger key, nothing is enqueued, and the run never gets a worker. The cleanup cron later fails it.

- Tell: triggered, `failed`, zero `audit_response` rows, and a sibling run for the same patient + trigger + template that did run.
- These are noise, not lost work. Don't requeue them unless the sibling also failed.
- In `job_executions`, "no row" for an old run means the row was pruned after `expires_at`, not that the job never existed. Only `status = 'failed'` is a real failure.

## Don't

- Don't change a trigger key to "fix" volume. Keys are an idempotency contract with v1; a new key re-runs every review v1 already did.
- Don't bulk-requeue across orgs without checking the queue's concurrency first.
