{% extends "base.html" %} {% block title %}Approval Queue — psyc{% endblock %} {% block content %}

Submission Approval Queue

{{ counts.pending }} pending · {{ counts.approved }} approved · {{ counts.rejected }} rejected

Nothing leaves psyc to an authority destination without a human signing off. Routing builds the payload, freezes it here, and waits. You approve — Courier dispatches and the Ledger records. You reject — nothing leaves, and the rejection is recorded too.

how to use this view

How to use. Each row is a payload waiting on you. Click the case to inspect it before deciding. Approve sends it now; Reject blocks it forever (the case can still be re-submitted later from CLI if appropriate).

What you're seeing. Pending submissions for destinations marked requires_approval=True — CERT-Bund by default, or all destinations when PSYC_REQUIRE_APPROVAL=1.

Why it matters. The dossier mandates a human gate before evidence reaches real authority systems. This is that gate. The frozen payload guarantees the reviewer approves exactly what gets sent — not a re-derived version that might have drifted.

pending ({{ counts.pending }}) approved ({{ counts.approved }}) rejected ({{ counts.rejected }}) all
{% if not rows %}

Queue is clear. Either nothing is pending, or no destination on the current cases requires approval. Set PSYC_REQUIRE_APPROVAL=1 to force every routable submission through this gate.

{% else %} {% for p in rows %} {% endfor %}
# Created Case Destination Payload TLP Hash Status Action
#{{ p.id }} {{ p.created_at.strftime('%Y-%m-%d %H:%M:%S') }} {{ p.case_id }} {{ p.destination_name }} {{ p.payload_kind }} {{ p.tlp.value }} {{ p.payload_hash[:12] }}… {{ p.status.value }} {% if p.status.value == 'pending' %}
{% else %} {{ p.reviewer or '—' }}{% if p.reason %} · {{ p.reason }}{% endif %} {% endif %}
{% endif %}
{% endblock %}