TARGET PROJECT: webhook — handoff note

Current configuration (only final, non-superseded choices):
{
  "scope_key": "global",
  "latest_by": "timestamp",
  "tie_policy": "last",
  "delete_wins": false,
  "allow_resurrection": false,
  "amount_mode": "delta",
  "precision": 2,
  "gap_policy": "ignore",
  "audit_duplicate": true,
  "order": "key",
  "max_age": 120,
  "inclusive_age": false
}

Fixed interface:
- Implement evaluate(payload) -> {entities: [{tenant, entity, value: string, deleted: boolean}], duplicates: [event_id]}.
- now is an integer; events contain id, tenant, entity, seq, ts, kind ("set"/"delete"), and amount as a nonnegative decimal string.
- Do not mutate input.

Algorithm contract:
1. Age filter: discard events where now - ts > max_age. Also discard equality (now - ts == max_age) because inclusive_age is false.
2. Deduplication after age filtering: scope_key "global" means deduplicate by id globally (not by tenant+id), keeping the first occurrence. Because audit_duplicate is true, append each duplicate event's id to duplicates, preserving encounter order.
3. Group retained events by (tenant, entity).
4. Ordering/ties within each group: latest_by "timestamp" means use ts as the chosen sort field. For ties on ts, retain the last event according to tie_policy "last". Process retained events in ascending ts order.
5. Per-group processing: initialize processed seq = 0, value = 0, deleted = false.
6. Gap handling: gap_policy "ignore" means process an event only when event.seq == previous processed seq + 1. Skipped events do not change the processed seq. Any processed event updates the processed seq.
7. Event effects for processed events:
   - delete: sets deleted = true.
   - set: updates only if not deleted, because allow_resurrection is false. When it updates, it resets deleted = false and, in delta mode, adds amount to value (it does not assign absolutely).
   - A blocked set after deletion still counts as processed for seq purposes if it passed the gap filter; it does not change value or deleted state.
8. delete_wins is false: do not force final deleted = true merely because a retained event is a delete. (General contract note, currently inactive: if delete_wins were true it would force final deleted = true if any retained event is a delete, even if gap-skipped, without changing value.)
9. Final value formatting: round value to precision = 2 decimal places using exact ROUND_HALF_UP. Return a fixed-point string with exactly 2 digits after the decimal point.
10. Entity ordering: order "key" means sort entities by (tenant, entity). (General alternative, not current: order "input" would use earliest retained original index in each group before tie filtering.)

Exceptions / boundary behaviors to preserve:
- Age equality is excluded under current settings.
- Duplicates are audited under current settings.
- Gap-skipped events are ignored for value/deleted/seq progression, subject to the inactive delete_wins note above.
- Sets cannot resurrect a deleted entity under current settings.

Unresolved items:
- None recorded in the target-project updates. All listed configuration keys have current values above.