TARGET PROJECT: invoice - HANDOFF NOTE

Current authoritative configuration (after all updates; superseded values discarded):
{
  "currency": "CAD",
  "rounding": "per_line",
  "duplicate_event": "first",
  "inclusive_limit": true,
  "max_refund_age_days": 30,
  "refunds_first": true,
  "refund_overflow": "cap",
  "void_is_tombstone": true,
  "order": "id",
  "fee_refundable": false,
  "min_invoice_cents": 10,
  "status_case": "lower"
}

Interface:
evaluate(payload) -> {invoices: [{id, charge, refunded, balance, status}]}
Do not mutate payload. Empty input produces {invoices: []}.

Input assumptions:
- Invoices have unique id, integer created day, currency, nonnegative decimal-dollar strings in lines, nonnegative fee_cents.
- Events are ordered, each with eid, kind (refund/void/restore), day, and nonnegative cents.

Algorithm with current choices:
1. Filter out invoices whose currency is not "CAD".
2. Convert each line dollar-string to cents using exact decimal ROUND_HALF_UP. rounding="per_line": round each line to cents before summing. Principal = that sum. charge = principal + fee_cents.
3. Skip invoices with charge below min_invoice_cents=10 (charge < 10 excluded; 10 included).
4. Deduplicate events by eid with duplicate_event="first": keep first occurrence/value/position, ignore later duplicates.
5. Reorder events: refunds_first=true stably moves all refund events ahead of all non-refund events, preserving relative order within each group.
6. Process events starting active:
   - void: makes invoice inactive/disables future refunds. void_is_tombstone=true: permanently prevents any subsequent restore from re-enabling it.
   - restore: has no re-enabling effect after a void under tombstone mode.
   - Earlier successful refunds are never undone by void/restore.
   - refund: only counts while active, and only if age = event.day - created is >=0 and within limit: age < 30, or age == 30 allowed because inclusive_limit=true (age <=30).
   - Refund ceiling: fee_refundable=false, so ceiling = principal only (fee excluded), i.e. max total refunded = principal. refund_overflow="cap": an oversized refund is capped at the remaining unrefunded ceiling amount, not rejected wholly.
7. balance = charge - refunded.
8. End status, status_case="lower":
   - "void" if inactive at end,
   - else "refunded" if refunded == charge,
   - else "open".
   Apply lowercase.
9. Sort output invoices by id ascending (order="id").

Exceptions / unresolved items: none recorded for target project. All other archived project settings in source records are unrelated and must be ignored.