Troubleshooting — plate reads aren't opening sessions

When a camera is wired up but plate reads aren't producing the sessions you expect, walk this checklist top to bottom — each step rules out the next.

**1. Is the camera writing events at all?**
`/parking → Cameras` → scroll to "Live plate events." If your reads aren't showing up at all, the ingest endpoint never accepted them. Common causes:
• Wrong `x-camera-key` header — rotate the key on the camera row and re-deploy your camera config.
• Wrong `cameraId` in the POST body — copy it from the row again.
• Camera status is `retired` — flip it back to `active` via Edit.

**2. Are events landing but getting dropped?**
The "Live plate events" feed shows every read. If the `processed` cell shows `processing…` for more than a few seconds, the trigger may have errored — check Cloud Functions logs for `onParkingPlateEventCreated`. If it shows an amber unmatched reason, one of these is fired:
• `empty_plate` — the OCR result normalized to an empty string. Tune your ALPR.
• `low_confidence` — the `confidence` field on the POST was below the camera's `confidenceMin`. Lower the floor if your lighting is rough.
• `duplicate_entry_read` — a second entry-direction read fired while a session was already open. Harmless, but check that your exit camera is also registered or the session will never close.
• `no_active_session_on_exit` — exit read with no open session at this lot for this plate. Usually means the entry camera missed the vehicle (try a wider field of view).

**3. Session opens but `linkedUserId` is empty**
That means no one with this plate has registered it on `/me/parking`. Auto-pay won't fire (there's no payment method), but the session still tracks duration and posts to the gate.

**4. Session closes but `paymentStatus: 'failed'`**
Stripe declined the off-session charge. The session writes `autoChargeError` with the underlying message — common cases are expired cards, blocked country, and 3DS-required cards. If the lot has `qrFallbackEnabled` on, the driver gets a QR URL automatically; otherwise enable it.

**5. Session closes but no expense line**
Walk the four conditions in "Auto-emit work-trip parking to your employer's expense report." The most common miss is forgetting to mark the trip as `work` on `/me/trips`.

**Test mode**
You can simulate a plate read without a real camera — `curl -X POST <ingestParkingPlateEvent> -H 'x-camera-key: pkc_...' -H 'content-type: application/json' -d '{"cameraId":"...","plate":"TEST123","direction":"entry"}'`. The Live plate events feed shows the synthetic read with a fake-looking timestamp; use this to confirm wiring before involving the actual hardware.