HANDOFF: scheduler

Scope: Only scheduler requirements are authoritative. Ignore all archived records for other projects. Updates 1–5 have been applied in order; superseded values are discarded. No later update or question is available.

CURRENT SETTINGS
{
  "timezone": "UTC",
  "cutoff_hour": 18,
  "cutoff_inclusive": false,
  "lead_minutes": 60,
  "adjacency_allowed": false,
  "duration_max": 90,
  "duplicate_policy": "last",
  "cancelled_blocks": false,
  "capacity": 2,
  "report_order": "input",
  "blackout_day": "2026-11-01",
  "priority_high_first": true
}

FIXED INTERFACE AND RULES
- Implement evaluate(payload) returning exactly {selected:[id], blocked:[id], rejected:[id]}.
- payload contains now (offset-aware ISO datetime) and appointments. Each appointment has id, start (offset-aware ISO datetime), positive duration in minutes, integer priority, and boolean cancelled.
- Do not mutate input.
- Deduplicate by id before processing. Keep the last value, while preserving the id's first insertion position. The retained row's original index is the actual input index of that last value, not the first insertion position.
- Process retained rows by priority descending. Break priority ties by retained original index.
- Perform start/end arithmetic in UTC elapsed minutes, never local wall-clock minutes. Use zoneinfo or equivalent timezone conversion.
- Duration must be >0 and <=90 minutes.
- Start must be >= now +60 elapsed minutes; equality is allowed.
- Convert start to UTC (the configured timezone) for calendar-day rules. Reject appointments starting on 2026-11-01 in that zone.
- Construct cutoff at 18:00 on start's local calendar day in the configured zone. End must be strictly before cutoff; equality is rejected.
- Cancelled appointments are rejected and do not reserve capacity. With current settings, blocked is always empty.
- Accept an otherwise valid appointment only if fewer than 2 already accepted intervals intersect it.
- Endpoint-only contact counts as overlap because adjacency_allowed=false.
- Capacity counts the number of intersecting accepted intervals, NOT peak simultaneous concurrency. A candidate intersecting two accepted intervals is rejected even if those two intervals do not overlap each other.
- Accepted noncancelled appointments go to selected. Invalid or capacity-conflicting ids go to rejected.
- Sort each output list by retained original index, not priority order or first insertion position. Deduplicated ids appear once, classified using the retained value.

UNRESOLVED / NOT SPECIFIED
- No current configuration key remains unresolved.
- Exact handling of malformed payload-level input (for example invalid now), ids that are missing/unusable, and the permitted id type is not specified.
- Numeric duration type beyond “minutes” is not specified; priority is explicitly integer.
- No implementation language, test suite, or additional output/error interface has been prescribed.
- Do not import defaults or acceptance rules from unrelated archives. Preserve these settings unless a later scheduler update explicitly replaces them.