HANDOFF NOTE: project "importer" (only this project; archived records for other projects were discarded as unrelated)

1. Interface and algorithm contract (fixed)
evaluate(payload) -> {records:[{id,fields}], audit:[string]}
Events: id (string), version (integer), deleted (boolean), fields (JSON object).

Algorithm, in order:
1. Normalize id: trim if trim_ids, then ASCII case folding iff fold_case.
2. Empty normalized id: skip it or raise ValueError, according to empty_id.
3. Do the normalization and empty check BEFORE discarding events with version < version_floor.
4. Deduplicate on normalized (id, version). The group keeps the position of its first insertion, but the selected event is the first or last of the group according to duplicate_policy. Sorting uses the selected event's actual original index.
5. Process events ordered by (version, selected original index).
6. Record each normalized id's first processed index.
7. Deletion: removes the record. With tombstone_wins, it also permanently blocks later non-deletions of that id.
8. A deletion is applied only if a record existed or it installs a new sticky tombstone. Redundant deletions are blocked (no change).
9. Non-deletion: merge fields, creating {} if needed.
   - A null value either is ignored or deletes the existing key, according to null_mode.
   - With nested_merge, two objects merge recursively; otherwise the new object replaces the old.
   - Two arrays: replace, or (list_merge=unique) append only new items not structurally JSON-equal to any item in the old array. New-array items are not deduplicated among themselves.
10. Filter top-level fields to name, tags, meta only iff unknown_fields=drop.
11. Audit: with audit_all, every processed event is recorded; otherwise only applied ones. Format: normalized_id:version:applied or normalized_id:version:blocked. Audit keeps processing order.
12. Record sort: order=id sorts lexically by normalized id; otherwise by first processed index, then id.
13. Input must not be mutated.

2. CURRENT settings (after Updates 1-5)
- duplicate_policy = "first"
- fold_case = true
- tombstone_wins = true
- trim_ids = true
- list_merge = "replace" (Update 5 overrode "unique" from Update 2)
- nested_merge = true (Update 4 overrode false from Update 2)
- null_mode = "ignore" (Update 4 overrode "delete" from Update 2)
- version_floor = 2 (Update 5 overrode 3 from Update 2)
- audit_all = true
- empty_id = "skip"
- order = "input" (so records sort by first processed index, then id)
- unknown_fields = "drop" (keep only name, tags, meta at top level)

All twelve keys have been set explicitly, so there are no defaults to guess.

3. Consequences worth remembering
- Under list_merge=replace, the unique-append rule is inactive. Arrays are simply replaced.
- Under null_mode=ignore, null values never delete keys.
- With version_floor=2, events with version < 2 are dropped after the id normalization and empty-id check.
- With empty_id=skip, no ValueError is raised for empty ids.

4. Exceptions and unresolved items
- No exceptions to the contract have been given.
- Unresolved: behavior for the cases below is not specified. Do not invent it; flag it if it arises.
  - How null interacts with nested objects when nested_merge is on (assumed same null_mode handling at each level).
  - Whether unknown_fields filtering applies before or after merging (the contract says filter top-level fields; the exact timing is unstated).
  - Behavior for malformed events, such as a wrong type or missing keys.
- Later updates replace only the keys they name; all other keys stay unchanged.

5. Instructions for the next session
Treat only "importer" updates as authoritative. Ignore any archive-* project records. Apply future updates by key-level override on the settings above.