ADR-0020: Overdue Task Escalation is Notify-Only — No Auto-Reassignment

Status

Accepted

Tags

fieldforce, overdue, escalation, notifications

Decision

When a fieldforce task remains overdue beyond the org’s escalation_after_hours threshold, the system sends a push notification to the next-role-up (supervisor → manager → admin) and sets escalated_at on the task. The task’s assigned_to is unchanged. The manager decides whether to reassign, extend the deadline, or cancel the task manually.

Why

Auto-reassignment requires answers to questions the system cannot resolve: which specific user in the next role receives the task, what happens to the original assignee’s accountability, and how to handle tasks that are nearly complete when escalation fires. These decisions require business context only a human manager has. Rejected alternatives:
  • Auto-reassign to next role: Changes assigned_to, creates an audit entry. “The manager” is not a single user in multi-manager orgs. Destructive if the original assignee was about to complete the task. Rejected.
  • Visibility-change escalation: Expand AllowedUserIDs so escalation targets can see the task. Adds a new scoping concept with no existing precedent. Rejected.

How it works

New columns on ff_tasks (migration 005):
Both default to NULL. Neither is included in API responses — they are internal job state. Per-org timing is read from org_module_configs (ADR-0019) on each tick. Defaults: overdue_notify_after_hours = 0 (notify immediately when overdue), escalation_after_hours = 24.

Known limitations

  • Single escalation: escalated_at is set once. If the task remains unresolved after escalation, no further automated action occurs. The manager must intervene.
  • 1-minute delay: Notifications fire within 1 minute of the threshold crossing, not instantly. For overdue_notify_after_hours = 0, the first notification may be up to 1 minute late.
  • Role resolution ambiguity: In orgs with multiple managers, all managers in the org receive the escalation notification. No single manager is designated.

Rules for agents

  • The escalation job MUST NOT change assigned_to, status, or any other task field — it only sets escalated_at and sends a notification
  • Tasks with status IN ('approved', 'cancelled') MUST be skipped in both passes — do not notify on terminal tasks
  • Both overdue_notified_at and escalated_at MUST be set atomically with the notification — if the notification fails, do not set the column (retry on next tick)
  • Do not expose overdue_notified_at or escalated_at in API responses — these are internal job state columns
  • Never send a second overdue notification or second escalation for the same task — the NULL check is the idempotency guard

Bad pattern (do not generate)

Good pattern