Task templates audit log
Every change to a task template (also called an operation_task) is now recorded in an audit log, viewable from the V28 admin surface.
Open: Admin → Audit Log → Task templates.
Why this exists
Task templates are user-owned configuration — the operator authored them, the operator owns them. Before gh#300, the operation_tasks table could be silently mutated by:
- Deploys that re-seeded templates (overwriting operator edits)
- LLM agents (Pulse Copilot / message_analysis) writing back changes during tool runs
- Scripts run during incident triage
- Duplicate-creation bugs (one template cloned 14 times in a single deploy window)
The operator had no way to see when a template changed, who changed it, or what the diff was. The audit log fixes that — every mutation now writes a row with actor + diff + timestamp, and the operator can review.
What's in the log
Each row:
| Column | What |
|---|---|
| Timestamp | When the change happened |
| Template | Slug + label of the affected template |
| Actor | manual:operator-<id> / deploy:<sha> / llm:agent-<name> / script:<filename> |
| Action | created / updated / deleted / activated / deactivated |
| Field diff | Per-field old → new (for updates) |
Click a row to expand the full diff and see the surrounding context (which deploy commit, which Pulse Copilot turn, which incident script).
Filtering
The audit log is filterable by:
- Template slug (e.g. show me everything that touched Rule 21 "Thank-you message")
- Actor type (only operator edits / only deploys / only LLM / only scripts)
- Date range
What gets caught
A few classes the operator wanted visible:
1. Silent deploy re-seeds
A deploy that re-applies seed data writes actor=deploy:<sha> rows. If the operator edited Rule 14 yesterday and a deploy this morning overwrote the edit, the audit log shows both rows — operator can re-apply.
2. LLM-driven writes
Pulse Copilot has a template.update tool. Every use of it writes actor=llm:agent-<name> with the Pulse Copilot turn ID so the operator can trace which conversation produced the change.
3. Duplicate creates
The duplicate-creation bug (gh#292 — 11 copies of one rule, gh#300 — 14 copies) is now visible: the audit log shows N created rows for the same slug in a single window.
A CI ratchet (gh#316) detects duplicate groups proactively — see admin/system-logs.md for the daily audit job's output.
Restore from history
For any update row, you can Restore to this version — applies the old field values back to the active template + writes a new audit row with actor=manual:operator-<id> and note=restore-from=<old-audit-id>.
Useful when a deploy reset something the operator had carefully tuned.
Implements: gh#301 (V28 operator UI for operation_tasks_audit_log).
Related: gh#300 (RCA — why this exists), gh#316 (duplicate detection ratchet), gh#321 (USER_OWNED_CONFIG registry framework), gh#333 (audit helper), gh#334 (extend to remaining tables).