TARGET PROJECT: webhook — HANDOFF NOTE

Current authoritative configuration (later target updates supersede earlier values; archived projects are unrelated and excluded):
{
  "scope_key": "tenant",
  "latest_by": "sequence",
  "tie_policy": "first",
  "delete_wins": true,
  "allow_resurrection": true,
  "amount_mode": "absolute",
  "precision": 0,
  "gap_policy": "accept",
  "audit_duplicate": false,
  "order": "input",
  "max_age": 60,
  "inclusive_age": true
}

Interface:
evaluate(payload) -> {entities: [{tenant, entity, value: string, deleted: boolean}], duplicates: [event_id]}
- payload includes integer `now` and events with: id, tenant, entity, seq, ts, kind ("set"/"delete"), amount (nonnegative decimal string).
- Do not mutate input.

Algorithm contract:
1. Age filter: discard events where now - ts > max_age. With inclusive_age=true, age exactly equal to max_age is kept; generally, discard equality unless inclusive_age.
2. Deduplication on remaining events: key is (tenant, id) when scope_key="tenant", otherwise id globally. Keep first occurrence. Append duplicate id to `duplicates` only if audit_duplicate; current setting is false, so duplicates list remains empty for duplicates, but deduplication still occurs. Preserve encounter order in `duplicates` when auditing is enabled by a future change.
3. Group retained events by (tenant, entity).
4. Ordering/ties within each group: latest_by chooses sort field — "sequence" means seq, otherwise ts. For ties on the chosen field, retain first according to tie_policy (retain last if tie_policy="last").
5. Process retained events in ascending order of the chosen sort field. Initialize seq=0, value=0, deleted=false.
6. Gap handling: with gap_policy="ignore", an event would be processed only when event.seq == previous processed seq + 1; skipped events do not change seq. Current gap_policy="accept", so this filtering does not apply. Any processed event updates seq.
7. Event effects:
   - delete: sets deleted=true. It does not directly change value.
   - set: updates only if not deleted, or if allow_resurrection=true (current). When it updates, it resets deleted=false and assigns amount in absolute mode (adds amount in delta mode; current mode is absolute).
8. delete_wins=true: force final deleted=true if any retained event in the group is a delete, even if a gap filter skipped that delete. Do not change value for this final override.
9. Rounding/output: round final value to `precision` decimal places using exact ROUND_HALF_UP. Return a fixed-point string with exactly `precision` digits; with current precision=0, no decimal digits.
10. Entity ordering: if order="key", sort by (tenant, entity). Current order="input": order by earliest retained original index in each group, measured BEFORE tie filtering.

Exceptions/current special behaviors:
- Resurrection is allowed.
- Delete-wins is final even over later/absolute sets and over gap-skipped deletes.
- Age boundary at exactly 60 is included.
- Duplicate auditing is off.

Unresolved items: None recorded. All 12 configuration keys above have current values.