Handoff: target project invoice

Authority: Only the fixed contract and updates explicitly targeting invoice apply. Updates 1–5 have been resolved below. Ignore all archived records for other projects. No later update or question is available yet.

CURRENT choices
{
  "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,
  "fee_refundable": false,
  "order": "id",
  "min_invoice_cents": 10,
  "status_case": "lower"
}

Fixed interface and input contract
- Implement evaluate(payload) -> {invoices:[{id,charge,refunded,balance,status}]}.
- Invoices have unique id, integer created day, currency, lines containing nonnegative decimal-dollar strings, nonnegative fee_cents, and ordered events.
- Each event has eid, kind (refund/void/restore), day, and nonnegative cents.
- Do not mutate payload.
- Empty input produces {"invoices":[]}.

Current processing requirements
1. Filter out invoices whose currency is not CAD.
2. Convert each line to cents with exact decimal ROUND_HALF_UP; round each line separately, then sum to obtain principal. Avoid binary floating-point rounding.
3. charge = principal + fee_cents. Skip invoices with charge < 10; charge exactly 10 is retained.
4. Deduplicate events by eid, keeping the first occurrence and its insertion position. Deduplication precedes event reordering.
5. Stably move all refunds ahead of all other events. Preserve relative order within refunds and within non-refunds; do not sort events by day.
6. Begin active, with refunded = 0.
7. A void makes the invoice inactive and permanently blocks subsequent restore. Earlier refunds are never undone.
8. Process a refund only while active and when 0 <= event.day - created <= 30. Negative age is invalid; age exactly 30 is allowed.
9. The refund ceiling is principal only: fees are not refundable. Cap each eligible refund at the remaining unrefunded ceiling.
10. Final status, lowercase:
    - "void" if inactive, regardless of prior refunds;
    - otherwise "refunded" if refunded == charge;
    - otherwise "open".
11. balance = charge - refunded.
12. Sort returned invoices by id. Return only id, charge, refunded, balance, status for each retained invoice.

Important interactions and exceptions
- Refund-first reordering occurs after deduplication and before processing. Thus surviving refunds are evaluated before any void, even if the original event order placed a void first.
- A later restore cannot reverse a void because void_is_tombstone is true.
- A fully refunded principal with a positive nonrefundable fee does not qualify for "refunded"; if active, status remains "open" and balance equals the fee.
- Invoice filtering uses total charge, including fee, not principal.
- All monetary output quantities are cents.

Unresolved / not specified
- No current choice key remains unresolved.
- Exact payload container schema beyond the stated invoice/event fields, validation/error behavior for malformed input, and id type/comparison semantics are not explicitly specified. Do not infer them from archived projects.
- Future invoice updates should replace only their named keys and leave all other current choices unchanged.