TARGET PROJECT: importer — HANDOFF NOTE

Current authoritative configuration (later updates supersede earlier values; unrelated archived projects ignored):
{
  "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"
}

Fixed interface:
evaluate(payload) -> {records: [{id, fields}], audit: [string]}
Events: id string, integer version, deleted boolean, fields JSON object.
No mutation of input.

Algorithm contract:
- Normalize id: trim only if trim_ids (current: false); ASCII case-fold only if fold_case (current: false).
- Empty normalized id: skip if empty_id="skip", raise ValueError if "error" (current: error).
- Normalize/empty-check BEFORE discarding events with version < version_floor (current: 3).
- Deduplicate by normalized (id, version), retaining first insertion position, but selecting first/last event per duplicate_policy (current: last). Sorting uses the selected event's actual original index.
- Process in order (version, selected original index).
- Save each normalized id's first processed index (for input ordering, though current order="id").
- Deletion: removes record; if tombstone_wins (current: false), it also permanently blocks later non-deletions. A deletion is applied only if a record existed or it installs a new sticky tombstone; redundant deletions are blocked/no-change.
- Otherwise merge fields, creating {} if needed.
- Null values: ignore or delete existing key per null_mode (current: delete).
- nested_merge (current: false): if true, recursively merge two objects; otherwise replace object.
- Arrays: replace, or if list_merge="unique" (current), concatenate items not equal to any existing old-array item. Equality is structural JSON equality. No deduplication among new-array items themselves.
- unknown_fields (current: keep): only if "drop", filter top-level fields to name, tags, meta.
- Audit: audit_all (current: false) records every processed event, otherwise only applied ones. Format: normalized_id:version:applied or normalized_id:version:blocked. Preserve audit processing order.
- Records output order: if order="id" (current), sort lexically by normalized id; otherwise by first processed index, then id.

Unresolved items: none recorded.