The Design: Contracts, Adapters, and Runners Strip a frontend quality platform down to its essentials and three separate concerns emerge: what should be checked, how a specific consumer app gets ready to be checked, and where the checking actually runs. Keep those three separate and the platform stays reusable without forcing every app to look identical. They become three building blocks: contracts , adapters , and runners . Contract: what should be validated A contract is the quality expectation, written once: open the account menu, capture its default, hover, and keyboard-focus states, confirm it's reachable by keyboard, compare it against the approved baseline. The point of a contract is that it's reusable. If five apps use the same shared component, the basic expectation for that component shouldn't be rewritten five times — the component owner defines it once, and each consumer inherits it and adds only what's specific to them. A contract is a shared agreement: when this UI shows up in a consumer, here's what we care about. That agreement is what lets quality scale across teams instead of being reinvented by each one. Adapter: how the consumer gets ready Every consumer app is different — different login flow, different seed data, different feature flags, a component reached by a direct route in one app and a multi-step workflow in another. None of that belongs hardcoded into the shared contract. Instead, each consumer supplies an adapter: how to start the app, how to authenticate, which of its routes map to which contract states, what should be masked because it's dynamic — a timestamp, an ad slot. The adapter is what lets a consumer keep control of its own environment while still plugging into the shared system. > Contracts make quality reusable. Adapters make it realistic. Reusable contracts without adapters ignore how real apps actually work. Adapters without contracts are just duplicated test setup with extra steps. Runner: where it actually executes The runner takes a contract and an adapter and runs the scenario for real: launches the browser, applies the right viewport, theme, and locale, waits for the UI to settle, captures screenshots and accessibility results, and reports everything in the same format every time. The runner's job is to be boring. It carries no business knowledge of its own — just execution. That's actually the point: when something fails, the team can ask one of three specific questions instead of "why did this random screenshot break" — did the contract describe the wrong thing, did the adapter set up the wrong environment, or did the runner itself misbehave? A contract can be as small as this, and still be enough to run: Small enough that a developer, a QA engineer, or a design system owner can read it — and review it in a pull request like any other change. Keep that vocabulary small on purpose; the moment a scenario format grows into a full programming language, fewer people can use it. The rule > Contracts define reusable expectations, adapters supply real consumer context, runners produce consistent evidence. Together they mean every app can plug into the same validation model without having to become identical to each other. Next: how these three pieces connect into an actual release pipeline.