## TL;DR
The event stream delivers duplicates, at-least-once is the norm, and the agent counts every delivery as a new transaction. Dedupe on the event id before any counting, and make the ledger check tolerant of replays. Velocity and amount features must count unique events, never raw deliveries, or every retry storm looks like a fraud wave.

```text
fraud agent double-counted duplicate transaction events and failed
```

## Use this when
- Velocity features spike without real volume growth.
- Ledger checks fail on totals that do not reconcile.
- Retried webhooks or replays inflate counts.

## Not for this skill when
- Duplicates are distinct transactions that look alike. Check the event ids first.
- The count is wrong for one transaction. That is a parsing problem.

## Steps
1. Dedupe at ingestion on the provider event id, before any feature computation. Verify: replaying the same event file twice changes no feature and emits no new alert.
2. Store processed event ids with a TTL longer than the max replay window. Verify: a replay from last week is still caught.
3. Make the ledger check replay-aware: reconcile on unique events, and log duplicates separately. Verify: the ledger passes with duplicates in the stream and flags the duplicate share in its report.
4. Monitor the duplicate rate itself: a sudden jump means an upstream retry storm. Verify: a dashboard shows duplicate share over time with an alert on sudden jumps.

## Variant phrasings
### duplicate events double counted
Ingestion phrasing.
### at-least-once delivery inflating velocity
Semantics phrasing.
### replayed webhooks broke ledger check
Replay phrasing.

Compatibility: Works with any event source that emits stable event ids. The dedupe store can be any key-value store with TTL, sized to the replay window.

## Why it happens
Pipelines promise at-least-once delivery and the agent was written as if delivery meant exactly-once. Every retry, replay, and redelivery becomes a phantom transaction in the features, and the ledger can never reconcile.

## Edge cases / pitfalls
- TTL too short misses slow replays. Size it to the longest upstream retry window.
- Some providers reuse event ids across event types. Key on id plus type.
- Dedupe at ingestion only, not at every stage, or you pay the cost repeatedly.
- Backfills look like duplicates. Whitelist backfill runs explicitly so they are not quarantined.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_waTZ7W6lNhksuxILy1liVw
