{"files":{"main.ts":"import {run} from './core.ts';\nimport {POLICY} from './policy.ts';\nexport function evaluate(payload: any): any { return run(payload, POLICY); }\n","core.ts":"import {parseDecimal, addDecimal, formatDecimal, compare} from './helpers.ts';\n\nexport function run(payload: any, policy: any): any {\n  const duplicates: any[] = [];\n  const seen = new Map<any, Set<any>>();\n  const groups = new Map<any, Map<any, any>>();\n  const field = policy.latest_by === 'sequence' ? 'seq' : 'ts';\n\n  for (let index = 0; index < payload.events.length; index++) {\n    const event = payload.events[index];\n    const age = payload.now - event.ts;\n    if (age > policy.max_age || (age === policy.max_age && !policy.inclusive_age)) continue;\n\n    const scope = policy.scope_key === 'tenant' ? event.tenant : null;\n    let ids = seen.get(scope);\n    if (!ids) {\n      ids = new Set<any>();\n      seen.set(scope, ids);\n    }\n    if (ids.has(event.id)) {\n      if (policy.audit_duplicate) duplicates.push(event.id);\n      continue;\n    }\n    ids.add(event.id);\n\n    let tenantGroups = groups.get(event.tenant);\n    if (!tenantGroups) {\n      tenantGroups = new Map<any, any>();\n      groups.set(event.tenant, tenantGroups);\n    }\n    let group = tenantGroups.get(event.entity);\n    if (!group) {\n      group = {tenant: event.tenant, entity: event.entity, firstIndex: index, selected: new Map<any, any>()};\n      tenantGroups.set(event.entity, group);\n    }\n    const sortValue = event[field];\n    if (!group.selected.has(sortValue) || policy.tie_policy === 'last') {\n      group.selected.set(sortValue, event);\n    }\n  }\n\n  const results: any[] = [];\n  for (const tenantGroups of groups.values()) {\n    for (const group of tenantGroups.values()) {\n      const events: any[] = Array.from(group.selected.values());\n      events.sort((a, b) => compare(a[field], b[field]));\n      let seq = 0;\n      let value = parseDecimal('0');\n      let deleted = false;\n      let hasDelete = false;\n      for (const event of events) {\n        if (event.kind === 'delete') hasDelete = true;\n        if (policy.gap_policy === 'ignore' && event.seq !== seq + 1) continue;\n        seq = event.seq;\n        if (event.kind === 'delete') {\n          deleted = true;\n        } else if (event.kind === 'set' && (!deleted || policy.allow_resurrection)) {\n          deleted = false;\n          const amount = parseDecimal(event.amount);\n          value = policy.amount_mode === 'absolute' ? amount : addDecimal(value, amount);\n        }\n      }\n      if (policy.delete_wins && hasDelete) deleted = true;\n      results.push({firstIndex: group.firstIndex, tenant: group.tenant, entity: group.entity, value: formatDecimal(value, policy.precision), deleted});\n    }\n  }\n\n  results.sort(policy.order === 'key'\n    ? (a, b) => compare(a.tenant, b.tenant) || compare(a.entity, b.entity)\n    : (a, b) => a.firstIndex - b.firstIndex);\n  return {\n    entities: results.map(({tenant, entity, value, deleted}) => ({tenant, entity, value, deleted})),\n    duplicates\n  };\n}\n","policy.ts":"export const POLICY: any = {\n  delete_wins: true,\n  latest_by: 'sequence',\n  scope_key: 'tenant',\n  tie_policy: 'first',\n  allow_resurrection: true,\n  amount_mode: 'absolute',\n  gap_policy: 'accept',\n  precision: 0,\n  inclusive_age: true,\n  max_age: 60,\n  audit_duplicate: true,\n  order: 'key'\n};\n","helpers.ts":"export type Decimal = {coefficient: bigint; scale: number};\n\nfunction power10(exponent: number): bigint {\n  return BigInt(10) ** BigInt(exponent);\n}\n\nexport function parseDecimal(text: string): Decimal {\n  const parts = text.split('.');\n  const fraction = parts[1] || '';\n  return {coefficient: BigInt((parts[0] || '0') + fraction), scale: fraction.length};\n}\n\nexport function addDecimal(a: Decimal, b: Decimal): Decimal {\n  const scale = Math.max(a.scale, b.scale);\n  return {\n    coefficient: a.coefficient * power10(scale - a.scale) + b.coefficient * power10(scale - b.scale),\n    scale\n  };\n}\n\nexport function formatDecimal(value: Decimal, precision: number): string {\n  let coefficient = value.coefficient;\n  if (value.scale > precision) {\n    const divisor = power10(value.scale - precision);\n    const remainder = coefficient % divisor;\n    coefficient = coefficient / divisor;\n    if (remainder * BigInt(2) >= divisor) coefficient += BigInt(1);\n  } else {\n    coefficient *= power10(precision - value.scale);\n  }\n  const digits = coefficient.toString();\n  if (precision === 0) return digits;\n  const padded = digits.padStart(precision + 1, '0');\n  return padded.slice(0, -precision) + '.' + padded.slice(-precision);\n}\n\nexport function compare(a: any, b: any): number {\n  return a < b ? -1 : a > b ? 1 : 0;\n}\n"}}