Disclosure Review & Release Governance

This guide is part of the Privacy-Preserving Spatial Analytics section. It covers the process that sits around the technical protections in the rest of the section — the review, checks and records that decide whether a spatial data product can leave the building, and that let a program show afterwards why it decided as it did.

Concept & Epidemiological Alignment

Every method elsewhere in this section protects a single product. Cell suppression protects one table; geomasking protects one point file; differential privacy protects one set of counts within a stated budget. Real disclosure risk rarely comes from a single product. It comes from combinations: a county table and a ZIP code table that together isolate a small area; this year’s release and last year’s that differ by one case; a dashboard filter that, set just so, shows a count the published table suppressed; a research extract joined with public data the analyst never considered.

Disclosure review is the practice of examining a release in the context of everything else that has been or will be released, before it goes out. It asks three questions. Does this product, on its own, meet the program’s rules? Does it, combined with other releases, allow any protected value to be recovered? And is the residual risk — there is always some — documented and accepted by someone with the authority to accept it?

Release governance is the structure that makes review routine rather than heroic. It defines who reviews, what evidence they need, which releases can be approved by standing rules and which need a board, and where the record of each decision lives. Without it, disclosure control depends on the diligence of whichever analyst happens to produce a table, and on their memory of what was published before.

The epidemiological stakes run both ways. Too little review risks re-identifying patients, which harms them directly and damages the trust that surveillance depends on: people who fear disclosure avoid testing and treatment. Too much review delays data that communities, researchers and partner agencies need, and pushes them to less careful sources. A good governance process is fast for routine releases and careful for novel ones, and it gets that balance from standing rules for the routine and a documented review for everything else.

Spatial data raise the stakes because geography is a powerful quasi-identifier. A count of three cases in a rural census tract, a date of diagnosis and an age band may identify a person to their neighbours even though no table contains a name. Every spatial release is therefore a potential re-identification risk, and the review has to reason about what local knowledge a reader could bring.

Method Choices

Control What it catches Cost
Standing release rules Routine tables meeting fixed thresholds Low; automatic approval
Automated rule checks Small cells, missing complementary suppression Low; runs in the pipeline
Differencing checks across releases Recoverable values from overlapping tables Moderate; needs a release register
Disclosure review board Novel products, research extracts, exceptions High; meets on a schedule
Residual risk statement Accepted risk recorded with an owner Low; a template
Fast for the Routine, Careful for the Novel A release request enters automated checks, which test small cells, complementary suppression and differencing against the release register. Routine releases that pass and match a standing rule are approved automatically and logged. Releases that are novel, fail a check or request an exception go to the disclosure review board, which approves, approves with changes or declines, and records a residual risk statement with an owner. Every outcome is written to the release register, which future checks read. Two paths, one register Release request product + context Automated checks cells, complements, differencing Standing rule routine, passes: auto-approve + log Review board novel, failing or exception requested Release register read by future checks the register is what makes differencing checks possible

Spatial Data Prerequisites

Disclosure review needs a release register: a structured record of every product released, with its geography, time period, stratification, suppression and masking applied, and the actual released values or a pointer to them. Without it, differencing checks are impossible, because there is nothing to check a new table against. The register should hold enough to recompute any released cell, stored securely, since the pre-suppression values are protected.

It needs a policy file that encodes the program’s rules — minimum cell sizes, which denominators trigger suppression, complementary suppression requirements, geographic minimums — in machine-readable form, as described in Mapping State Small-Cell Rules Into a Policy File. Automated checks read the policy; the board interprets it where it is silent.

It needs geographic hierarchy and crosswalk files for every geography the program publishes: tracts, ZIP Code Tabulation Areas, counties, health districts, legislative districts. Differencing risk arises where geographies nest imperfectly, so the review has to know exactly how a tract splits across ZIP codes and districts.

And it needs population counts at every geography, because risk depends on the population behind a count, not only the count. Five cases in a tract of 8,000 is a different risk from five cases in a block group of 400.

Production Implementation

The automated part of review runs as a pipeline step that takes the candidate product, the policy file and the release register, and returns a structured finding list. Findings either clear the release for a standing rule or route it to the board.

# Automated pre-release disclosure checks against policy and release register.
# Pinned: pandas==2.2.2, numpy==1.26.4, pyyaml==6.0.1
import logging
from dataclasses import dataclass, field

import numpy as np
import pandas as pd
import yaml

logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("disclosure_review")


@dataclass
class Finding:
    check: str
    severity: str          # "block" or "review"
    detail: str


@dataclass
class Review:
    product_id: str
    findings: list[Finding] = field(default_factory=list)

    @property
    def route(self) -> str:
        # Any finding sends the release to the board; "block" findings must be
        # fixed or granted an exception there, "review" findings need judgement.
        return "board" if self.findings else "standing_rule"


def check_small_cells(tbl: pd.DataFrame, policy: dict, r: Review) -> None:
    k = policy["min_cell"]
    shown = tbl["count"].notna()
    small = shown & (tbl["count"] > 0) & (tbl["count"] < k)
    if small.any():
        r.findings.append(Finding("small_cells", "block", f"{int(small.sum())} cells below {k}"))


def check_complements(tbl: pd.DataFrame, r: Review) -> None:
    """A suppressed cell must not be the only suppressed cell in its row or column group."""
    for key in ("row_group", "col_group"):
        per = tbl.groupby(key)["count"].apply(lambda s: int(s.isna().sum()))
        lone = per[per == 1]
        if len(lone):
            r.findings.append(Finding("complementary", "block",
                                      f"{len(lone)} {key}s with a single suppressed cell"))


def check_differencing(tbl: pd.DataFrame, register: pd.DataFrame, xwalk: pd.DataFrame,
                       policy: dict, r: Review) -> None:
    """Flag geographies where a new table and a registered one differ by a small remainder."""
    prior = register[(register["measure"] == tbl.attrs["measure"]) &
                     (register["period"] == tbl.attrs["period"])]
    if prior.empty:
        return
    new_on_common = tbl.merge(xwalk, on="geoid").groupby("common_id")["count"].sum(min_count=1)
    old_on_common = prior.merge(xwalk, on="geoid").groupby("common_id")["count"].sum(min_count=1)
    diff = (new_on_common - old_on_common).abs()
    risky = diff[(diff > 0) & (diff < policy["min_cell"])]
    if len(risky):
        r.findings.append(Finding("differencing", "review",
                                  f"{len(risky)} common areas recoverable as a small remainder"))


def review(tbl: pd.DataFrame, register, xwalk, policy_path: str) -> Review:
    policy = yaml.safe_load(open(policy_path))
    r = Review(product_id=tbl.attrs["product_id"])
    check_small_cells(tbl, policy, r)
    check_complements(tbl, r)
    check_differencing(tbl, register, xwalk, policy, r)
    log.info("product=%s findings=%d route=%s", r.product_id, len(r.findings), r.route)
    return r

The differencing check is necessarily approximate. It compares the new table with registered tables for the same measure and period on a common geography built from the crosswalk, and flags areas where the difference is a small positive number — the signature of a value recoverable by subtraction. It catches the common cases. The full method, including overlapping geographies and time periods, is in Detecting Differencing Attacks Across Published Tables.

The board’s part is procedural: a checklist, a quorum and a record, covered in Running a Disclosure Review Board Checklist. What the board accepts it must document, and the form that documentation should take is in Documenting Residual Disclosure Risk for a Release.

Two Safe Tables, One Disclosure A county table shows forty-two cases in county A. A health district table, published separately, shows thirty-nine cases in a district that covers county A except for one small town. Each table passes the small-cell rule on its own. Subtracting the district from the county gives three cases in the small town, a value below the suppression threshold that neither table shows directly. The differencing check catches this by comparing both tables on a common geography. Each table passes; together they fail County table County A: 42 passes: 42 ≥ 11 − District table District 4: 39 passes: 39 ≥ 11 = Small town 3 recovered district 4 = county A minus one town, so the town's count is exposed only a register of past releases and a crosswalk reveal this

Parameter Selection & Tuning

Which releases get standing rules. Candidates are products released repeatedly in a fixed format: monthly county counts, annual tract rates, dashboard tiles at a fixed geography. Each standing rule names the product, geography, measures, thresholds and checks it must pass. Anything outside those parameters goes to review, however small the change.

Differencing tolerance. A difference below the minimum cell size flags a potential disclosure. Some programs also flag differences below twice the minimum, since a remainder of 12 in a population of 300 can still be sensitive. Tune by the population of the remainder area, not the count alone.

Board cadence. A board that meets monthly suits research extracts and novel products. An emergency response needs a faster path: a small standing subgroup with authority to approve time-critical releases, whose decisions the full board reviews afterwards.

Register retention. Differencing risk persists as long as prior releases are available, which on the internet is indefinitely. Keep the register for as long as any registered product is publicly available, and in practice for the life of the program.

Look-back scope. Checking a new release against every past release is expensive. Scope the look-back to releases that share a measure and overlap in time and geography; that covers almost all practical differencing risk and keeps the check fast enough to run in the pipeline.

Edge Cases & Failure Modes

Dashboards and interactive tools. A dashboard is not one release but every combination of filters it allows. Review the dashboard’s query space: the finest geography, the smallest strata, and whether a filter combination can produce a suppressed cell by subtraction from two others. Enforce suppression on the server, not in the browser, where a user can read the underlying data.

Releases by other agencies. A county health department may publish its own counts at a geography the state never used. Differencing against those is outside the state’s register but not outside the risk. Where partners publish related data, share release schedules and geographies, and include their products in the register if possible.

Corrections and revisions. Revising a published table after late case reports creates a pair of tables that differ by the late cases — sometimes exactly one. Treat a revision as a new release subject to differencing against the version it replaces, and consider publishing revisions only at coarser geographies or after a fixed lag.

Research extracts. Extracts released under a data use agreement to a named researcher are protected by the agreement rather than by suppression. They still need review of what the researcher could combine them with, and the agreement must forbid linking and re-identification.

Staff turnover. The analyst who knew which tables were published last year leaves. The register, the policy file and the board’s records are what survive. A governance process that lives in people’s memories fails at exactly the moment new staff start producing releases.

Pressure during emergencies. During an outbreak, demand for fine-grained, fast data is intense and review can feel like an obstacle. Pre-approve emergency products — which geographies, which measures, which thresholds — before the emergency, so the fast path is already defined.

Most Releases Should Never Reach the Board A horizontal bar divides a year's releases by route. About eighty-two percent passed automated checks under a standing rule and were approved the same day. About fourteen percent went to the review board, with a median of nine days to decision. About four percent used the emergency subgroup, with a median of one day. A healthy process keeps the board for the releases that need judgement. A year of releases by route 82% standing rule same day 14% board, 9 days 4% emergency, 1 day standing rules keep the board's time for releases that need judgement

Compliance & Audit Controls

For every release, the register records the product, geography, period, measures, the checks run and their findings, the route taken, the approver, any residual risk statement, and the release date and channel. For board decisions, it also records the members present, the evidence considered and the decision with its conditions.

The policy file is versioned, and each release records the policy version it was checked against, so a later change in rules does not cast doubt on releases made under earlier ones. Standing rules are reviewed at least annually, and whenever a disclosure incident or near miss occurs.

Disclosure incidents — a release later found to reveal a protected value — are recorded with their cause and the change made to prevent recurrence. The purpose is learning, not blame: most incidents trace to a gap in the register or a combination nobody anticipated, and each one improves the checks.

Production Implementation Checklist

Frequently Asked Questions

Is a disclosure review board necessary for a small program? A small program may not need a formal board, but it needs the same functions: someone other than the analyst reviews novel releases, the decision is recorded, and a register of releases exists. Two people and a shared spreadsheet can do this well.

Can automated checks replace human review? For routine products under standing rules, yes. For novel products, exceptions and research extracts, automated checks provide evidence but cannot judge context — what local knowledge a reader might have, or what another agency has published.

How far back should differencing checks look? As far as any overlapping product is still publicly available. In practice, scope the check to releases sharing a measure and overlapping in time and geography.

What if a past release is found to be disclosive? Withdraw or replace it where possible, record the incident with its cause, assess whether affected individuals must be notified under applicable law, and update the checks so the same combination is caught next time.

Does differential privacy remove the need for review? It removes the need for differencing checks among products released under a shared, tracked privacy budget. Products released outside that budget — suppressed tables, research extracts — still need review against the DP releases and each other.