Decide

Decisions, questions and suppressions

Some tables a check flags are mistakes. Some are public on purpose. Decisions let your team say which is which once, and every later check remembers. Everything you decide goes into the check’s signed receipt.

Who can decide

Any member of the workspace that the app belongs to, once the check has finished. Decisions and answers belong to monitored apps, so a free check that isn’t linked to an app can’t take them (the API answers 403). To record decisions, add the repo as an app first.

The easiest place is the report itself. Open a check of your app while signed in and a Your decision panel appears under the result: tick the tables it applies to, then press Approve the fix, or These are meant to be readable… and say why. Business questions appear in the same panel with a box for each answer. Everything below can also be done with the API, using your signed-in session.

Approve or reject

Approve
“Yes, this is a leak and we’re applying the fix.” It records who approved which tables and when, and removes those tables from the app’s suppressions if they were there.
Reject
“These tables are meant to be readable.” For example, a public directory of shops. The tables are remembered for this app as intended (a suppression), and later checks stop alerting on them.
Approve every flagged table
curl -s -X POST https://api.patchlabs.dev/checks/$CHECK_ID/decision \
  -H "Authorization: Bearer $PL_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{"action": "approve", "reason": "Applying the fix in PR #42"}'
Mark one table as intended
curl -s -X POST https://api.patchlabs.dev/checks/$CHECK_ID/decision \
  -H "Authorization: Bearer $PL_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{"action": "reject", "tables": ["shops"], "reason": "Shop listings are public by design"}'

tables is optional. Left out, it means every table the check flagged. If you name tables, each one must be a table this check flagged, or the API answers 422 with “This check didn’t flag …”. The response lists every decision on the check so far:

201 Created
{"decisions": [
  {"action": "reject", "tables": ["shops"], "reason": "Shop listings are public by design",
   "by": "Priya", "at": "2026-11-10T09:12:44.120391+00:00"}
]}

What a suppression changes

A rejected table stays suppressed for that app until someone approves it on a later check. Here is exactly what that does, and doesn’t, change today:

WhereEffect of a suppression
Diff between checksListed under suppressed, left out of new_leaks and still_leaking
EmailsNo “New leak found” subject for it; listed as “marked as intended by your team”
WebhooksListed in check.suppressed
App detailsListed in suppressed_tables
Check status and badgeUnchanged. The check still reports the table in tables_leaking, its status stays done or needs_review, and a public badge shows “fix in progress”
GitHub ActionUnchanged. With fail-on-leak, the step still fails on that status

Business questions

Most of the moments where a person is needed aren’t technical. They are questions only the owner can answer, so the report asks them in plain English with a recommended answer. For example:

Should sellers’ email addresses be visible to every signed-in buyer? Recommended: no, show them only to buyers with an order.

The questions are listed in the check’s summary.questions_for_owner. Answer them with the question text exactly as it appears there:

Terminal
curl -s -X POST https://api.patchlabs.dev/checks/$CHECK_ID/answers \
  -H "Authorization: Bearer $PL_SESSION" \
  -H 'Content-Type: application/json' \
  -d '{"answers": [{"question": "Should sellers’ email addresses be visible to every signed-in buyer?",
                    "answer": "No. Only buyers with an order."}]}'
  • Each question must match one of the check’s questions, or the API answers 422. A check with no questions answers 409.
  • Answering the same question again replaces the earlier answer (the receipt shows the latest, with who and when).
  • You can send up to 50 answers in one call.

Everything is signed

Decisions and answers appear in GET /checks/{id} (as decisions and answers) and in the check’s signed receipt. Each one records by, the member’s name (or their email if they haven’t set one), and at, the time. If a member later deletes their account, by reads “a former member”.

Changing your mind

Decisions are a history, not a setting: new ones are added, nothing is edited. To stop treating a table as intended, approve it on any check of the same app that flagged it. From then on it alerts again like any other leak.

Updated 10 Nov 2026Something unclear or wrong? Tell the founder