Enforced in the query
Suppression happens in the database query, not as a display filter that a different code path could bypass.
Reporting
Reporting answers operational questions — how many checks, at which location, with what outcome mix — from counters that were never per-patron rows in the first place.
01 · Shape
There is no table of individual verifications to aggregate from. The outcome-bearing tables are upsert-a-counter tables, which makes them structurally incapable of holding a per-patron record — not merely empty of one.
02 · Suppression
A row reading “one fail at this location on this day”
identifies a person to anyone who was there, even with no name attached. So
rows below a minimum group size of k = 3 are withheld.
Suppression happens in the database query, not as a display filter that a different code path could bypass.
API responses, exports, and the shared contracts re-assert the threshold, so a new consumer cannot accidentally inherit an unsuppressed view.
There is no owner-level override and no support-tier bypass. The highest privilege in the system still sees a suppressed row.
03 · Exports
Exports are JSON rather than spreadsheet formats. Every field is typed and controlled, so there are no free-text cells and no formula-injection surface in a file that will inevitably be opened in a spreadsheet somewhere.
Volume by location and day. Outcome mix and how it moves. Which sites are carrying the load. Whether the unable-to-verify rate changes after a staffing change, a hardware move, or an app update.
Anything about an individual. Repeat visits, cross-location behavior, a specific check at a specific minute, or who was refused. Those questions have no data to answer them, by design.
Pilot reporting runs the same suppression rules as production. There is no looser data mode.