HANDOFF NOTE: project "webhook" (only this project's requirements are authoritative)

1. Task contract (fixed)
Implement evaluate(payload) -> {entities:[{tenant,entity,value:string,deleted:boolean}], duplicates:[event_id]}.
Inputs: now (integer); events with id, tenant, entity, seq, ts, kind (set/delete), amount (nonnegative decimal string). The input must not be mutated.

Algorithm:
1. Age filter: discard an event if now-ts > max_age. Also discard it when now-ts == max_age unless inclusive_age is true.
2. Dedup the remaining events, keeping the first. The key is (tenant,id) if scope_key=tenant, otherwise id globally. Append the duplicate id to duplicates (in encounter order) iff audit_duplicate.
3. Group by (tenant,entity).
4. latest_by selects the sort field: seq or ts. On ties in that field, retain the first or last event per tie_policy.
5. Process retained events ascending by the chosen field. Initial state: seq=0, value=0, deleted=false.
6. If gap_policy=ignore, process an event only when event.seq == previous processed seq+1. Skipped events leave seq unchanged. Any processed event updates seq.
7. A delete sets deleted=true. A set updates only if not deleted or allow_resurrection is true. A set resets deleted=false and assigns the amount (absolute mode) or adds it (delta mode).
8. delete_wins: if any retained event is a delete (even one skipped by the gap filter), final deleted=true. The value is unchanged.
9. Finally round value to `precision` decimal places with exact ROUND_HALF_UP. Return a fixed-point string with exactly that many fractional digits (no decimal point when precision is 0).
10. Entity ordering: if order=key, sort by (tenant,entity). Otherwise sort by the earliest retained original index in each group, measured BEFORE tie filtering.

2. CURRENT settings (after Updates 1-5)
- delete_wins = true (Update 1)
- latest_by = "sequence", i.e. sort field seq (Update 1)
- scope_key = "tenant" (Update 1)
- tie_policy = "first" (Update 1)
- allow_resurrection = true (Update 4; supersedes the false from Update 2)
- amount_mode = "absolute" (Update 4; supersedes delta from Update 2)
- gap_policy = "accept" (Update 5; supersedes ignore from Update 2). No gap filtering: all retained events are processed.
- precision = 0 (Update 5; supersedes 2 from Update 2)
- audit_duplicate = false (Update 5), so duplicates is always an empty list
- order = "input" (Update 5), i.e. earliest retained original index before tie filtering
- inclusive_age = true (Update 3), so events with now-ts == max_age are kept
- max_age = 60 (Update 3)

3. Notes and caveats
- "sequence" for latest_by means the seq field. The contract's value name is "seq"; treat "sequence" as an alias for it.
- With precision 0, values have no decimal point.
- Archived records for other projects (archive-east/west/north/south-NN) were ignored as unrelated.
- No exceptions or special cases were given beyond the above.

4. Unresolved items
- None currently known. Later updates replace only the keys they name; unnamed keys stay unchanged. The next update and further questions are not yet available.