pattern

Consent Enforcement Point

also called Preference Chokepoint, Lowest Common Reader

The lowest layer every reader of a dataset must pass through - the only place a user preference can be enforced so that it also binds readers who do not exist yet.

consentprivacyblast radiusdata access layerforeseeable harm

A product ships a "hide my activity" control. The web client reads the flag and stops rendering the row. The feed service still returns the activity in its response, because the control was built where it was visible.

Three weeks later a partner integration reading the same endpoint displays it publicly. Nothing errors; every service behaves as specified. The user did use the control and the control did not do what it said - a worse failure than a control nobody adopted.

Why it matters

Count the readers of a mature data endpoint and you find 8 to 12: web, iOS, Android, a partner API, edge-cached responses, the search index, a nightly export, and the feature pipeline behind recommendations. Enforcing a preference in one of them delivers about 1 of 8 of a control while the product page says the control exists.

The harm is foreseeable at design time, which makes this an ethics question rather than a bug. The reader that caused the disclosure did not exist when the control shipped - the ordinary case, because endpoints acquire readers. Remediation is asymmetric too: a code fix stops the flow and does not recall copies.

Implementation patterns

  • Enforce in the data access path, not above it: a row-level filter, a database security policy, or a predicate the repository applies unconditionally - somewhere no caller can route around.
  • Keep a readers register - every system reading this dataset, with an owner - so "who has a copy" is a ten-minute answer rather than archaeology.
  • Fail closed on an unreadable preference. If the consent lookup errors, withhold; the opposite choice discloses during a partial outage, when nobody is reading privacy alerts.
  • Put the preference in the cache key, or an edge-cached response becomes an uncontrolled copy for the full TTL - days, on a long-lived key.
  • Test with a client you did not write - a curl with a valid token catches the opening example in two minutes.

Industry example

Published incidents involving support and impersonation tooling share one shape: a capability is built by reusing the normal read path, the limiting control is applied in the interface staff use, and the underlying path stays reachable by anything holding a credential. A control applied in a user interface constrains one client and nothing else, and it recurs because the interface is where a control is easiest to demonstrate.

Regulatory drafting reached the same point from the other side: the EU AI Act (Regulation 2024/1689) requires high-risk systems to be technically capable of automatically recording events over their lifetime, rather than requiring an operator to describe the behaviour. The obligation sits on the mechanism, not on the account of it.

Failure scenarios

  • The new reader. A partner integration or internal tool reads the unfiltered path months later and coverage silently drops.
  • The analytics copy. The warehouse took the data before suppression, so a dashboard shows what the user hid.
  • Fail-open on lookup error, producing a disclosure window during a brief consent-service outage that no error budget covers.

Trade-offs

Choose Gains Pays
Enforce in the data access path binds every reader including future ones; one place to change semantics every read is conditional; cache keys grow; shared code several teams must respect
Enforce per client simple; no change to shared read paths coverage equals the share of clients you wrote; new readers default to exposure

The honest cost lands in the query layer: a mandatory predicate on a high-volume read path affects every plan and complicates caching.

When not to use it

When the preference is cosmetic - theme, density, notification sound, default sort. Those belong in the client; pushing them into the query layer makes every read conditional for no protection.

When the data is public by definition. A seller's published listing has no hide semantics; manufacturing one creates a control users will believe does more than it can. And when the enforcement point sits below a boundary you do not control - data already with a processor - the mechanism is contractual rather than architectural.

Interview question

Q: "A privacy control is enforced in your web client. Convince me that is adequate, then tell me what you would measure to find out whether it is, and what you would change first."

What a strong answer covers: the honest case for client-side enforcement when the preference is cosmetic; the measurement - enumerate the readers and compute the covered share, almost always 1 of 8 to 12; then the change - predicate in the data access path, preference in the cache key, fail closed on lookup error, readers register built.

Quick check

Quiz: A hide-activity control is read by the web client while the feed service still returns the data. What is its coverage? The share of readers you wrote - typically 1 of 8 to 12; apply the predicate unconditionally in the data access path instead.

Flashcard: Where must a preference be enforced to bind a reader written next year, and what must the cache key carry? - At the lowest layer every reader passes through; the key must include the preference or the cache becomes an uncontrolled copy for its TTL.