Governance
A design system is a living contract. Governance is the discipline that keeps that contract honest. Three principles guide every call we make: the lowest-friction proposal, the fastest possible no, and the smallest viable yes.
| Triage SLA | 3 working days |
| Discussion window | 2 weeks maximum |
| Minor release | Thursdays, 14:00 UK |
| Major release | Two weeks’ notice, with migration guide |
| Deprecation cycle | One minor version, minimum |
| Lint rules in CI | Three – all blocking |
Roles
Four roles, each with a clear surface they own and a clear surface they don’t. Reach the role, not the person – inboxes are aliased so coverage doesn’t depend on who’s online.
Sets direction. Final call on breaking changes.
Owns: roadmap, semver discipline, conflict resolution, the changelog.
Does not own: day-to-day reviews, brand identity, individual component APIs.
Review proposals. Ship token and component releases.
Owns: triage, code review, release notes, lint rules. Two named people minimum, never one.
Does not own: direction, brand identity, breaking-change decisions.
Anyone in the org may propose.
Owns: the proposal, the use case, the draft. Engineers, designers, editors, marketing – all welcome.
Does not own: approval, scheduling, the API surface of shipped components.
Open an issue on the repo
Owns the magazine voice and visual identity.
Owns: logo, primitive colour, type, photography direction. Can veto colour and type changes.
Does not own: component APIs, semantic tokens, accessibility rules.
Decision RACI
The same six decisions come up again and again. The grid below is the answer key – Responsible, Accountable, Consulted, Informed. Disputes refer back to this table before they escalate.
| Decision | Responsible | Accountable | Consulted | Informed |
|---|---|---|---|---|
| Add a primitive token | Brand custodian | System lead | Maintainers | Contributors |
| Add a semantic token | System lead | System lead | Maintainers | Brand custodian |
| Add a component | Maintainers | System lead | Contributors | Brand custodian (if visual) |
| Rename a token | System lead | System lead | Maintainers, Brand custodian | Contributors |
| Deprecate a token | Maintainers | System lead | Maintainers | Contributors |
| Patch a docs typo | Anyone | Maintainer on review | – | – |
How to propose
The shape of every proposal is the same: what, why, where, who else might use it. If a proposal can’t answer those four, it isn’t ready. The templates below ship as issue forms on the repo.
Token proposal
Open an issue with the W3C DTCG JSON snippet, the use case, and the alternative considered. The form mirrors the existing token files so review is mechanical.
## What
A new semantic token: `color.feedback.notice.surface`.
## Token (W3C DTCG)
{
"color": {
"feedback": {
"notice": {
"surface": {
"$value": "{color.mustard.100}",
"$type": "color"
}
}
}
}
}
## Why
The notice banner pattern needs a calmer surface than `feedback.warning.surface`.
Mustard 100 reads as informational without alarm.
## Where
Subscriber communications banner, billing-state notices, scheduled-maintenance ribbon.
## Who else
Editorial workflow notices, in-product release notes.
## Alternative considered
Reusing `feedback.info.surface` – rejected because the cool blue reads as system, not editorial.
Component proposal
Open an issue with five things: a problem statement, three product references, a sketch (low-fi is fine), the API surface, and accessibility considerations. Sketches do not need to be Figma frames – paper photos pass triage.
## Problem
Editors saving long interviews can't see how many words have been added since the last save.
## References
1. Google Docs – word-count diff in the footer.
2. Notion – per-block change indicator.
3. Internal sketch from issue 84 retro.
## Sketch
[attach – paper, Figma, screenshot, all fine]
## API surface (proposed)
<WordCountDiff
baseline={number}
current={number}
variant="inline" | "footer"
ariaLabel={string}
/>
## Accessibility
- Live region: polite, announces every 30s of typing.
- Visible focus ring matches `border.focus`.
- Reads "added 240 words since last save" – not "+240".
Pattern proposal
Patterns aren’t tokens or components – they’re recipes. Propose in a doc PR with a draft of the patterns page entry. The PR is the proposal.
Review process
Five stages. The clock runs on triage and discussion only. Build takes as long as it takes – we’d rather ship the right thing late than the wrong thing on time.
- 01
Triage – within 3 working days
A maintainer asks three questions: is this a duplicate, is it in scope, is it the right tier? Outcomes: accepted for discussion, redirected, or closed with a one-line reason.
- 02
Discussion – two weeks maximum
At most two maintainers in the thread. We converge or close. Proposals stalled past two weeks default to “not now” – the author can re-open with new evidence.
- 03
Spike – optional
A branch with a minimal implementation, behind a feature flag. Used when the design works on paper but the API surface is uncertain. Spikes are time-boxed to one week.
- 04
Build & docs
Implementation, docs page, tests, tokens, lint rules. The four ship together or not at all – a component without docs is not shippable.
- 05
Ship
Version bump, changelog entry, release note in #design. Beta first for new components – four weeks minimum before stable.
What’s breaking vs additive
The semver contract is the heart of the system. See /design/changelog/ for the full rules. The short version, written for proposers:
Renaming color.brand.primary to color.brand.accent.
Removing the variant=“ghost” prop from Button.
Inverting spacing.tight from 4px to 12px.
Adding color.feedback.notice.surface.
Adding a new WordCountDiff component.
Adding variant=“quiet” to an existing Button.
Fixing a contrast ratio that fell below 4.5:1.
Correcting a misspelled token in docs.
Restoring the focus ring lost in a refactor.
Breaking changes need a major bump and a deprecation cycle of at least one minor version. The deprecated surface emits a console warning, ships a codemod where possible, and is removed only in the next major.
The lint discipline
Three rules run in CI on every PR. They block merge. Maintainers don’t override – they fix or send back. See /design/naming/ for the rule definitions and the regex behind each. The governance angle:
“Failing in CI means we caught it before users did.”
Lint catches the patterns no human reviewer can hold in their head – tier crossing, naming drift, forbidden values. Trust it.
”Just this once – the rule is being annoying.”
If a rule is wrong, fix the rule. If the rule is right, fix the code. The third option – overriding for one PR – is how systems silently rot.
Token & component lifecycle
Every primitive moves through the same seven stages. Targets below are the ones we hold ourselves to – missed targets are a maintenance signal, not a failure.
- Proposal Open-ended Issue opened with the templated form. Author drafts what, why, where, who else.
- Triage ≤ 3 working days Duplicate, in scope, right tier? One maintainer responds.
- Spike ≤ 1 week Optional. Minimal branch, behind a flag. Time-boxed.
- Beta ≤ 4 weeks Shipped behind a flag or namespaced as `*-beta`. Real use, real feedback.
- Shipped Indefinite Stable. Documented. Linted. Recommended in patterns.
- Deprecated ≥ 1 minor version Console warning, codemod where possible, replacement named in the changelog.
- Removed Major release Major version only. Migration guide published two weeks before release.
When to escalate
Most disagreements resolve in the issue thread. The ladder below is for the ones that don’t. Every escalation closes with a written rationale – the next person to hit the same fork should not have to re-litigate it.
| Conflict | Resolves to | Output |
|---|---|---|
| Two maintainers disagree on a review | System lead | One-paragraph decision, posted on the issue. |
| System lead and Brand custodian disagree | Joint call within a week | Written rationale either way, recorded in the changelog or governance log. |
| A token is used outside its tier | Blocked by lint automatically | If recurring, a maintainer flags the pattern – never the person. |
| A proposal stalls past two weeks | Defaults to “not now” | Author can re-open with new evidence; no judgement implied. |
| A breaking change is shipped without a deprecation cycle | Reverted, no exceptions | System lead writes the post-mortem within five working days. |
Versioning cadence
Predictable cadence is half the contract. Anyone integrating the system should know when to expect a release and what shape it will take.
| Release type | When | Who can cut |
|---|---|---|
| Patch | Any time | Any maintainer |
| Minor | Thursdays, 14:00 UK – entries close 12:00 | Two maintainers, paired |
| Major | Scheduled, two weeks’ notice, with migration guide | System lead, with paired maintainer |
Communication
Four channels, each with a single job. If you can’t tell which channel a message belongs in, default to the issue – it has the longest memory.
Every release announced here, with a link to the changelog entry. Quick questions welcome – long ones move to issues.
Every proposal lives here – tokens, components, patterns, bug reports. The issue is the source of truth, not the Slack thread.
Tuesdays 10:00 UK. Open to all. Agenda posted 24h ahead in #design – walk-ins welcome, but agenda items get the time.
The source of truth. Every change, every version, every deprecation. If it isn’t in the changelog, it didn’t ship.
Usage rules
Six habits that keep proposals moving and the system coherent. Read once, then refer back when a review feels stuck.
”Add a notice surface token.”
Each issue tracks one decision. Bundling five token requests into one issue stalls all five – discussion forks, history blurs.
”Add notice, success-quiet, warning-loud, info-bold and danger-soft – all related.”
Related is not the same as one decision. Five tokens means five discussions, five trade-offs, five places they’ll be used.
”Notice surface – billing, scheduled maintenance, editorial workflow.”
The system loves shared use cases. A token used in three places earns its keep – one used in one place is a candidate for an inline value.
”It’s just a 2px tweak – I’ll merge it.”
The system reads small additions cumulatively. Ten “just a 2px tweak” merges later, the rhythm is gone.
”Proposal includes the draft /design/components/word-count-diff/ entry.”
Maintainers approve faster when the docs are already shaped. The draft answers half the review questions before they’re asked.
”Brand custodian’s no on visual identity is final, with rationale.”
Voice and visual identity are deliberately not democratic. The custodian writes the rationale; the rationale enters the governance log; the conversation closes.
”CI failed – the rule caught a real tier crossing. Fix and re-push.”
Lint failures are signal, not bureaucracy. They’re how the system tells you the rule you’re proposing already conflicts with the one you wrote last quarter.
”It’s blocking my PR – can someone disable the rule?”
The rule is doing its job. The fix is upstream – either in the code, or in a proposal to change the rule with the same templated form.