Every engineering team I've met says privacy comes first. Almost none of their architectures agree.

You can see it in the shape of the system. Privacy and accessibility live in a checklist that runs late — a pre-launch audit, "quality week," a compliance sign-off bolted onto the end of a pipeline that was designed around throughput. We say these things are non-negotiable, then we build systems that treat them as negotiable light up until someone catches it.

I've spent two decades building systems that serve more than a billion people, and the lesson that took me the longest to accept is this: privacy and accessibility are not policies you enforce. They are constraints you design against, the same way you design against latency or memory. If they aren't in the architecture, they aren't in the product — no matter what the handbook says.

Here's why that's harder than it sounds.

Privacy gets exponentially harder as you scale

At a small scale, privacy is tractable because one team can hold the whole data flow in their heads. They know what's collected, where it goes, and who touches it. At scale, that mental model is gone. You have dozens of services emitting billions of events a day, and every new pipeline is a new place personal data can leak — usually not through a breach, but through a well-meaning engineer who logged one field too many.

Location makes this concrete. People assume you can anonymize a location trail by stripping the name off it. You can't. Human mobility is nearly unique: a handful of timestamped points — home, work, the route between —identifies a specific person with startling reliability. Coarsening the coordinates degrades the very product that needs them (navigation is precision), and classic anonymity guarantees fall apart on sparse, high-dimensional data like movement. So "just anonymize the location data" isn't a task you assign. It's an architectural decision about what you never collect in the first place.

Deletion is the other place the illusion breaks. Engineers think of deleting user data as one operation. It isn't — it's a distributed-systems problem. A single delete has to propagate to backups, caches, search indexes, derived aggregates, replicas, and any model you trained on that data. Encryption is one write.

Deletion is a graph traversal across every system that ever saw the record. If you didn't design for it up  front, "delete my data" becomes a quarter of engineering work instead of an API call.

Accessibility bugs are engineering bugs — that's why they slip

The reason accessibility regressions escape automated testing isn't that teams don't care. It's that our test oracles assert the wrong contract.

Picture a button that loses its accessibility label in a refactor. Every functional test still passes: the button renders, the tap fires, the state changes, the screen looks right in the diff. The behavioral contract holds perfectly. But to a user navigating by screen reader, that button now announces nothing — it's a dead spot on the screen. The bug is invisible to your test suite because your assertions checkbehavior, and the thing that broke is semantics.

That reframes accessibility from a UX nicety into an engineering problem with a technical fix: you have to assert the accessibility tree, not just the UI state. Contrast ratios, focus order, dynamic-type reflow, screen-reader labels — these are all measurable and all automatable. But only if you decide the accessibility contract is a first-class assertion, not something a human eyeballs once before release.

Trust is an architectural property, not a feature

The deepest version of this is that trust doesn't come from a single decision. It accumulates — or erodes — across thousands of small defaults.

On-device processing is the clearest example of trust as architecture. Moving computation onto the device isn't a toggle you flip; it moves work onto constrained hardware and rewrites the data flow around a hard invariant: the server never sees this. That single constraint cascades into everything — model size, sync strategy, what you can log, how you handle failure. You cannot retrofit it. Either the system was designed so the sensitive data never leaves the device, or it wasn't.

And trust erodes the same way it's built: quietly. Not through one dramatic leak, but through the steady accumulation of moments where the easy path sent a little more data than the feature actually needed. Each one  is defensible in isolation. Together they are the gap between what your team says and what your architecture does.

What automation should actually enforce

The mistake I made for years was trying to automate judgment. You can't. What you can automate — and must — are the invariants that are cheap to check and catastrophic to miss.

Data minimization is the best candidate. Instead of hoping code review catches an over-collected field, make iit a build-time invariant: a telemetry event is only allowed to carry fields it has declared. Anything extra fails the build.

# A telemetry event may only carry fields on its declared allowlist.   # An undeclared field is a privacy regression — caught at build time,   # not six months later in an audit.   ALLOWED_FIELDS = {"event_name", "timestamp", "os_version", "session_id"}   def assert_no_undeclared_fields(event: dict) -> None:                           leaked = set(event) - ALLOWED_FIELDS       if leaked:           raise PrivacyRegression(               f"Telemetry event carries undeclared fields: {sorted(leaked)}"           )

That's twelve lines, and it does more for privacy than any policy document — because it turns "remember to check" into "the build won't pass." The same shape works for accessibility (assert every interactive element exposes a label) and for location precision (assert coordinates are fuzzed below a threshold before they're persisted). Automate the invariant, not the intention.

Where humans still matter

Automation catches the violations you already know how to name. It cannot tell you whether a new feature's data collection is proportionalto the value it delivers, or whether an accessibility accommodation actually serves the person it's meant for, or whether a trade-off you've never seen before is acceptable. Those are judgment calls, and judgment doesn't compile.

So the goal isn't to remove humans from the loop. It's to spend their attention well — let the build enforce the known invariants automatically, and reserve expert review for the genuinely new decisions, made by someone with the domain depth to weigh them. Automation handles the rules. Experts handle the exceptions. Most teams have that backwards: humans manually re-checking the same known rules every release, and no one with the authority or context to catch the novel risk.

The takeaway

Performance stopped being the hard part of scaling a while ago. Trust is the constraint now — and trust is not a value you profess; it's a property your architecture either has or doesn't.

If privacy and accessibility live in a checklist at the end of your pipeline, they are features you can cut under deadline. If they live in your build gates and your data flow, they're constraints — as real as latency, and just as hard to argue with. That's the difference between a system that says users can trust it and one that's actually built to earn it.