Appearance
Appeals
Appeals in the current production model are represented as status, not as a dedicated table. There is no appeals table and no appeal-specific RPC; an appeal is a report (docket) in the Appealed status, and a punishment can carry the Appealed status. This page documents exactly what exists.
How an appeal is represented
Docket appeals
A report can be moved to the Appealed status by an agent with manage_dockets clearance via PATCH /reports/<id>/update (the manual pre/post-investigation status set is Open/Pending/Appealed — see _PATCHABLE_MANUAL_STATUSES in reports_service.py). The dashboard's status dropdown offers Appealed as a manual status:
- while an investigation is not started:
Open,Pending,Appealed; - while an investigation is in progress:
Open,Pending,Under Investigation,Appealed; - after conclusion:
Open,Pending,Appealed(manual changes are limited to reopening or appealing).
Appealed dockets behave as closed for dashboard aggregation (format.ts groups closed, validated, invalidated, appealed as closed), and the Analytics and Dashboard pages report appealed counts separately. Global Search has an appeal: resource that searches dockets whose status is exactly Appealed.
Changing the status writes the standard update path: timeline row ("Status updated" → "Status changed to: Appealed"), updated_at bump, and the canonical report.status_changed event with the pre/post status.
Deciding an appeal
The decide_appeal permission (clearance 4, CLEARANCE_POLICY in authz.py) gates the parts of the system that decide appeals:
- The global audit log (
GET /audit) requiresdecide_appeal— appeal review happens against the audit history. - The Audit Log page's event-type filter includes an
Appealscategory (tokens: "appeal").
There is currently no dedicated "decide appeal" endpoint or appeal-resolution state transition in the API. An appeal is resolved by moving the docket out of the Appealed status (for example back to Open/Pending, or to a concluded status), which any agent with manage_dockets + assignment can do through the normal update path.
Punishment appeals
The punishment status enum includes Appealed (PUNISHMENT_STATUSES in punishment_service.py): a punishment under appeal carries that status, and it is editable via PATCH /punishments/<id> (EDITABLE_PUNISHMENT_FIELDS.status) with the required audit reason. Revocation of an appealed punishment goes through the normal revoke endpoint. The report_id link on a punishment is the documented relationship appeals build on (types.ts: "Optional linked report (appeals will build on this relationship)") — no separate appeal join table exists.
Needs confirmation
The exact production workflow for filing an appeal (who files, how it enters the system) is not implemented as a distinct API surface in the current codebase — the demo seed contains "Appeal filed" timeline events and appealed dockets, and the dashboard treats Appealed as a manual status, but there is no appeal-specific endpoint. If a separate appeal workflow is required, it must be added and this page updated with it.
Who can interact with an appeal
| Actor | What they can do |
|---|---|
Any agent with manage_dockets + assignment | Set a docket to Appealed; move it out of Appealed via the normal update path |
Agents with clearance 4 (decide_appeal) | Review the global audit log (the appeal-decision surface) |
Agents with manage_punishments (4) | Set a linked punishment to Appealed; edit or revoke it with a reason |
| The assigned agent / supervisor ranks | All report updates are additionally gated by assignment |
Status changes and audit/event behavior
- Docket appeal status changes follow the standard
PATCH /updatecontract: timeline row +report.status_changedcanonical event with before/after state, written by the API after the table update. - Punishment status changes (
Appealedincluded) go throughrpc_punishment_update: field whitelist, required reason, before/afteradmin_audit_logrow (actionpunishment.edit), and the canonicalpunishment.updatedevent — all validated inside the database. - Revocation writes
punishment.revokedviarpc_punishment_revoke.