HANDOFF NOTE: project "webhook" (target only)

1. Scope
Only project webhook is authoritative. The many "archived work record" entries concern other projects (archive-west/east/north/south-*) and were discarded. Their settings must not be applied here.

2. Fixed contract (unchanged)
evaluate(payload) -> {entities:[{tenant,entity,value:string,deleted:boolean}], duplicates:[event_id]}
- Payload has now (integer) and events with id, tenant, entity, seq, ts, kind (set/delete), amount (nonnegative decimal string).
- Do not mutate the input.

Algorithm:
1. Age filter: discard an event if now-ts > max_age. Also discard if now-ts == max_age unless inclusive_age is true.
2. Deduplicate the remaining events, keeping the first. The key is (tenant,id) if scope_key=tenant, otherwise id globally. Append the duplicate id to duplicates iff audit_duplicate. Duplicates keep encounter order.
3. Group by (tenant,entity).
4. Within a group, sort by latest_by (seq or ts) ascending. For ties, retain first or last per tie_policy. Tie filtering happens before processing.
5. State starts as seq=0, value=0, deleted=false.
   - If gap_policy=ignore, process an event only when event.seq == previous processed seq+1. Skipped events do not change seq.
   - Any processed event sets seq to its seq.
   - Delete sets deleted=true.
   - Set updates only if not deleted or allow_resurrection. It resets deleted=false, then assigns amount (absolute mode) or adds amount (delta mode).
   - delete_wins: forces final deleted=true if any retained event is a delete, even if the gap filter skipped it. It does not change value.
6. Final value is rounded to precision decimal places with exact ROUND_HALF_UP. Output is a fixed-point string with exactly precision digits (no decimal point when precision is 0).
7. Entity order: if order=key, sort by (tenant,entity). Otherwise sort by the earliest retained original index in each group, measured BEFORE tie filtering.

3. CURRENT effective configuration (after Updates 1-5)
- delete_wins = false (Update 1)
- latest_by = "timestamp" (Update 1; sort field is ts)
- scope_key = "global" (Update 1; dedupe by id only)
- tie_policy = "last" (Update 1)
- allow_resurrection = false (Update 4 overrode Update 2's true)
- amount_mode = "delta" (Update 4 overrode Update 2's absolute)
- gap_policy = "ignore" (Update 5 overrode Update 2's accept)
- precision = 2 (Update 5 overrode Update 2's 0)
- audit_duplicate = true (Update 5)
- order = "key" (Update 5)
- inclusive_age = false (Update 3)
- max_age = 120 (Update 3)

4. Notes on interactions (derived, not new requirements)
- latest_by=timestamp sorts by ts. The gap_policy=ignore check still uses event.seq against the previously processed seq. With ts ordering, events may therefore be skipped if seq is not consecutive.
- With allow_resurrection=false, a set after a delete is ignored. It does not change value or deleted.
- With max_age=120 and inclusive_age=false, an event with now-ts==120 is discarded, same as now-ts>120.

5. Unresolved / open items
- No exceptions or unresolved issues were stated so far.
- No default values were given for keys never set. All twelve keys have been set by updates.
- The next update and later questions are not yet available. Later updates replace only the keys they name.