HANDOFF NOTE: target project "importer" (only this project; archive-* records are unrelated and discarded)

1. INTERFACE
evaluate(payload) -> {records:[{id,fields}], audit:[string]}
Event: id string, integer version, deleted boolean, fields JSON object.
Inputs must not be mutated.

2. CURRENT CONFIG (after Updates 1-5)
- duplicate_policy = "last"
- fold_case = false
- tombstone_wins = false
- trim_ids = false
- list_merge = "unique"
- nested_merge = false
- null_mode = "delete"
- version_floor = 3
- audit_all = false
- empty_id = "error"
- order = "id"
- unknown_fields = "keep"

Every key now has a value. The payload may still supply options; these are the current settings in force. Later updates replace only the keys they name.

3. ALGORITHM CONTRACT (fixed)
1. Normalize id: trim if trim_ids, then ASCII case folding if fold_case. Under the current config neither applies, so the id is used as given.
2. Empty normalized id: raise ValueError (empty_id=error). With "skip" it would be skipped instead. Do this check before the version-floor discard.
3. Discard events with version < version_floor (currently 3).
4. Deduplicate on normalized (id, version). The group keeps the first insertion position, but the selected event is the last one (duplicate_policy=last). Sorting uses the selected event's actual original index.
5. Process in order of (version, selected original index).
6. Record each normalized id's first processed index.
7. Deletion events:
   - Remove the record.
   - With tombstone_wins, also block later non-deletions permanently (currently off, so no sticky tombstones).
   - A deletion is applied only if a record existed or it installs a new sticky tombstone. Otherwise it is blocked/no-change.
8. Non-deletion: merge fields, creating {} if needed.
   - Null value: delete the existing key (null_mode=delete). With "ignore" it would be skipped.
   - Two objects: nested_merge is false, so the new object replaces the old. With nested_merge true, merge recursively.
   - Two arrays: list_merge=unique appends only new items not structurally equal (JSON equality) to any item in the old array. New-array items are not deduplicated among themselves.
   - Otherwise the new value replaces the old.
9. unknown_fields=keep: keep all top-level fields. With "drop", filter to name, tags, meta only.
10. Audit: audit_all=false, so only applied events are listed. With true, every processed event is listed. Format is normalized_id:version:applied or normalized_id:version:blocked. Audit keeps processing order.
11. Records: order=id sorts lexically by normalized id. Otherwise sort by first processed index, then id.

4. NOTES AND UNRESOLVED
- No exceptions or special cases beyond the contract were given.
- Ambiguities not settled by the spec (decide conservatively and document): whether null handling applies inside nested objects (moot while nested_merge is false); how a null merges when it replaces an object or array; whether a "blocked" event can appear in the audit when audit_all=false (spec says only applied events are shown).
- Later updates and questions are not yet available. Apply each as a key-by-key replacement and leave other keys unchanged.