TARGET PROJECT: scheduler — HANDOFF NOTE

Current authoritative configuration (after all target updates; superseded and unrelated archived-project values discarded):
{
  "timezone": "America/New_York",
  "cutoff_hour": 17,
  "cutoff_inclusive": true,
  "lead_minutes": 30,
  "adjacency_allowed": true,
  "duration_max": 120,
  "capacity": 1,
  "report_order": "id",
  "blackout_day": "2026-11-02",
  "cancelled_blocks": true,
  "duplicate_policy": "first",
  "priority_high_first": false
}

Fixed interface:
- Implement evaluate(payload) -> {selected:[id], blocked:[id], rejected:[id]}.
- payload contains now (offset-aware ISO datetime) and appointments.
- Each appointment contains id, start (offset-aware ISO datetime), positive duration in minutes, integer priority, and cancelled boolean.
- Do not mutate input.
- Use zoneinfo or equivalent timezone conversion.

Algorithm contract:
- Deduplicate appointments by id using duplicate_policy; current policy is "first". Retained row's original index is the retained value's actual original index.
- Process deduplicated appointments stably by priority. Because priority_high_first=false, sort priority ascending; ties use retained original index.
- Compute start/end with UTC elapsed minutes, not local wall-clock minutes. Duration must be >0 and <=duration_max (120).
- Start must be >= now + lead_minutes (30 minutes).
- Convert start to configured timezone (America/New_York). Reject an appointment whose local start date is blackout_day (2026-11-02).
- Define cutoff as cutoff_hour:00 (17:00) in the configured timezone on the start's local calendar day. Because cutoff_inclusive=true, end must be <= cutoff.
- Cancelled handling: because cancelled_blocks=true, a cancelled appointment is not automatically rejected; if otherwise acceptable and capacity permits, it can reserve capacity and is reported in blocked instead of selected. If cancelled_blocks were false, it would be rejected.
- Capacity: an appointment may be accepted only if fewer than capacity (1) already-accepted intervals overlap it. Count intersecting accepted intervals, not peak concurrency.
- Overlap: because adjacency_allowed=true, intervals sharing only an endpoint do not overlap.
- All invalid or capacity-conflicting appointments go to rejected.
- Sort each output list according to report_order; current order is "id", so sort selected, blocked, and rejected by id.

Exceptions / boundary rules to preserve:
- End exactly at 17:00 local cutoff is allowed.
- Start exactly at now+30 minutes is allowed.
- Duration exactly 120 is allowed; duration <=0 is invalid.
- Adjacent intervals touching only at an endpoint do not consume overlapping capacity.
- Cancelled appointments that pass other checks occupy capacity as blocked entries.

Unresolved items:
- None in the provided target updates. All 12 configuration keys above are currently set.