Reporting

Numbers you can act on. Records you cannot leak.

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

Counters, in two tiers.

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.

Tier Grain
verification_totals Cumulative, per location and outcome
verification_aggregates The same, with a day bucket added
per-check row does not exist at any tier

02 · Suppression

A small enough count is an individual record.

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.

Enforced in the query

Suppression happens in the database query, not as a display filter that a different code path could bypass.

Re-checked on the way out

API responses, exports, and the shared contracts re-assert the threshold, so a new consumer cannot accidentally inherit an unsuppressed view.

Applies to every role

There is no owner-level override and no support-tier bypass. The highest privilege in the system still sees a suppressed row.

03 · Exports

Typed JSON, deliberately.

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.

What an export can never contain

  • Name
  • Date of birth
  • Address
  • Portrait or photo
  • Document number
  • Wallet identifier
  • Mobile-ID payload
  • Session transcript
  • Patron identifier
  • Repeat-visitor identifier

What you can answer with it

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.

What you cannot answer with it

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.

Next step

Look at real reporting during a pilot.

Pilot reporting runs the same suppression rules as production. There is no looser data mode.