Skip to content

[#199] Auto-close stale escalations with no officer response - #200

Merged
dedenbangkit merged 1 commit into
mainfrom
feature/199-auto-close-stale-escalations
Sep 29, 2026
Merged

dedenbangkit merged 1 commit into
mainfrom
feature/199-auto-close-stale-escalations

Conversation

@dedenbangkit

@dedenbangkit dedenbangkit commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Closes #199

Summary

  • Daily Celery beat task tasks.ticket_tasks.auto_close_stale_tickets at 20:00 EAT (17:00 UTC). It closes open tickets older than ticket_auto_close.stale_hours (default 24) that have no officer reply, meaning no from_source = USER message for that customer since the ticket was created.
  • Tickets with any officer reply are never auto-closed. Auto-closed tickets keep resolved_by = NULL, so they can be told apart from officer-resolved tickets.
  • Farmer notification, sent once per farmer even with several stale tickets:
    1. ticket_auto_close Twilio template ({{1}} = officer label), EN HX80d2…d392 / SW HX58b6…c3
    2. otherwise free text (ticket_auto_closed in whatsapp_messages.json), only inside the WhatsApp 24h window
    3. otherwise not sent (logged); the ticket still closes. A send failure never stops the run.
  • officer_label config ({"en": "Extension Officer", "sw": "Afisa Ugani"}) parameterises the role name, e.g. "Health Worker" for the health sector. The existing ticket_closed message now uses it too; it previously hardcoded "extension officer".
  • Feature flag: ticket_auto_close.enabled.
  • Docs: docs/TICKET_AUTO_CLOSE.md.

Deviation from the issue

No ticket_resolved WebSocket event is emitted. Socket.IO connections live in the backend process with no Redis manager, so the Celery worker cannot reach dashboard clients. Auto-closed tickets appear as resolved on the next reload.

Before deploying

  • Add officer_label and whatsapp.templates.ticket_auto_close (sid, sid_sw) to the Vault-injected config.json for the test and production clusters, then restart backend and celery-worker
  • Confirm both Twilio templates are Approved for WhatsApp
  • Have a Swahili speaker review "Afisa Ugani" and the SW fallback text
  • Run a read-only count of the tickets the first run will close. The flag defaults to enabled when the key is missing, so the first 20:00 EAT run closes the whole backlog. Set ticket_auto_close.enabled: false in Vault to hold it.

Test plan

  • 15 new tests in tests/test_ticket_auto_close.py: selection (stale, answered, reply before ticket, under threshold, configurable threshold, already resolved), notification (template, free text in window, outside window, officer label, Swahili, one message per farmer, send failure), disabled flag, beat schedule
  • New test in test_tickets.py: manual resolve message uses the officer label
  • Full backend suite: 1161 passed
  • flake8 clean

🤖 Generated with Claude Code


…sponse

Add a daily Celery beat task (20:00 EAT / 17:00 UTC) that closes open
tickets older than ticket_auto_close.stale_hours (default 24) with no
officer reply since the ticket was created. Tickets with any officer
reply are never auto-closed; auto-closed tickets keep resolved_by NULL.

Each affected farmer is notified once via the ticket_auto_close Twilio
template, falling back to free text only inside the WhatsApp 24h
window.

Parameterise the responder role name via officer_label (e.g. "Health
Worker"), also used by the existing ticket_closed message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@dedenbangkit
dedenbangkit merged commit 4aaa81b into main Sep 29, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto-close stale escalations with no officer response after 24h

1 participant