Review that scales with the stakes
Make approving a risky agent write take more than one click, flag approvals made too fast to have been read, and see which reviewers skip the checks.
- See what an approval asks for at each risk level
- Turn the check from a warning into a requirement
- Find reviewers who approve without reading
A person who approves forty routine comments in a row will approve the forty-first, and the bulk close of 150 tickets after it, with the same click. Review friction asks for more where more is at stake, so an approval of a risky write is evidence that someone read it.
What an approval asks for
Every held write has a risk score from 0 to 100 and the factors behind it (see Approval auto-triage). The score sets the stakes:
| Stakes | Risk | What approving asks for |
|---|---|---|
| Low | below 40 | Nothing extra |
| Medium | 40 to 59 | At least 4 seconds with the request open |
| High | 60 or more | At least 10 seconds open, a tick against each risk factor, and for a call on a list of 10 or more items, the number of items typed in |
The item count is never shown next to the question: the approver has to read it from what will be sent. In the console's approvals inbox, Approve and run stays off until every box is ticked and the count is filled in. Rejecting never asks for anything.
GET /api/approvals and GET /api/approvals/{id} return review_required with stakes, risk, checks (the factors to confirm), min_review_s and asks_count. A client sends the review with the decision:
POST /api/approvals/{id}/approve
{"digest": "…", "review": {"checked": ["write", "bulk", "bulk_large"], "count": 150, "dwell_ms": 24000}}Warn or enforce
TICKETIQ_APPROVAL_REVIEW_FRICTION decides what happens to an approval that skipped the check or came too fast:
| Mode | Effect |
|---|---|
warn (default) | The approval goes ahead. The decision records the review and the row agent.approval.review.flagged names what was missing |
enforce | An approval through the API without the review is refused with 428 and told what to check. The request stays pending |
off | No check and nothing recorded |
In warn nothing that approves today needs a new step: Teams cards, the mobile app and scripts work as before. enforce needs every client that approves through the API to send the review: the console does; update the mobile app and any script first. A channel that cannot ask for the check, such as a Teams card, is recorded and audited in every mode, never refused.
A batch approval sends no review, so in enforce a high-risk request in a batch is refused even with allow_high_risk: approve it on its own.
On the record
The review (stakes, checked, too_fast, dwell_s, and via: console or channel) is stored on the decision and carried on its trust ledger receipt. Reviewer metrics (GET /api/approvals/metrics, agents.read and audit.read) count, per reviewer, unchecked_high_risk and too_fast approvals next to the rubber-stamp flag.