Interpretation notes: the payload has `now` (an integer) and `jobs`. I assume `now` is read from `payload.now`, and jobs from `payload.jobs`.

Dedup: keep the last job per key value, at its original index. The result is ordered by original index.

Classification order:
1. Cancelled: if `cancelled` is set and (`cancel_wins` or the job is not retryable), the job goes to cancelled. A cancelled retryable job with `cancel_wins` false continues to the later checks.
2. Dead: stale, `attempt >= max_attempts`, or a nonzero non-retryable `last_code`.
3. Otherwise compute due. A retryable job with a failure (`last_code` nonzero, which retryable codes always are) gets due = max(due, failed_at + min(base_delay * factor, cap)). With exponential false the factor is 1.
4. If due > now the job is waiting with `at` = due, else ready.

Stale check: with `stale_inclusive` false, dead when `now - created > stale_after`.

Missing `failed_at` or `due` defaults to 0.

Ready sort: priority ascending (`priority_high_first` false), then created descending (`fifo_ties` false), then original index. Dead order is by input index.

```json
{"files":{"main.ts":"import {run} from './core.ts';\nimport {POLICY} from './policy.ts';\nexport function evaluate(payload: any): any { return run(payload, POLICY); }\n","policy.ts":"export const POLICY: any = {\"base_delay\":200,\"cancel_wins\":false,\"dead_order\":\"input\",\"dedup_key\":\"key\",\"delay_cap\":400,\"exponential\":false,\"fifo_ties\":false,\"max_attempts\":4,\"priority_high_first\":false,\"retryable_codes\":[408,503],\"stale_after\":2000,\"stale_inclusive\":false};\n","helpers.ts":"export function cmp(a: number, b: number): number { return a < b ? -1 : a > b ? 1 : 0; }\n","core.ts":"import {cmp} from './helpers.ts';\nexport function run(payload: any, policy: any): any {\n  const now = payload.now;\n  const jobs: any[] = payload.jobs || [];\n  const last = new Map<any, number>();\n  jobs.forEach((j, i) => { last.set(j[policy.dedup_key], i); });\n  const sel: {j: any, i: number}[] = [];\n  jobs.forEach((j, i) => { if (last.get(j[policy.dedup_key]) === i) sel.push({j, i}); });\n  const ready: any[] = [], waiting: any[] = [], dead: any[] = [], cancelled: any[] = [];\n  for (const s of sel) {\n    const j = s.j;\n    const code = j.last_code || 0;\n    const retry = policy.retryable_codes.includes(code);\n    if (j.cancelled && (policy.cancel_wins || !retry)) { cancelled.push(s); continue; }\n    const age = now - j.created;\n    const stale = policy.stale_inclusive ? age >= policy.stale_after : age > policy.stale_after;\n    if (stale || j.attempt >= policy.max_attempts || (code !== 0 && !retry)) { dead.push(s); continue; }\n    let due = j.due || 0;\n    if (retry) {\n      const f = policy.exponential ? Math.pow(2, Math.max(0, j.attempt - 1)) : 1;\n      const d = (j.failed_at || 0) + Math.min(policy.base_delay * f, policy.delay_cap);\n      due = Math.max(due, d);\n    }\n    if (due > now) waiting.push({s, at: due}); else ready.push(s);\n  }\n  ready.sort((a, b) => {\n    let c = cmp(a.j.priority, b.j.priority);\n    if (policy.priority_high_first) c = -c;\n    if (c) return c;\n    c = cmp(a.j.created, b.j.created);\n    if (!policy.fifo_ties) c = -c;\n    if (c) return c;\n    return a.i - b.i;\n  });\n  if (policy.dead_order === 'id') dead.sort((a, b) => cmp(a.j.id, b.j.id) || a.i - b.i);\n  return {\n    ready: ready.map(s => s.j.id),\n    waiting: waiting.map(w => ({id: w.s.j.id, at: w.at})),\n    dead: dead.map(s => s.j.id),\n    cancelled: cancelled.map(s => s.j.id)\n  };\n}\n"}}
```