Concepts — Contributing to Chromium
Phase 6 · Spec areas §24 (contribution workflow), §49 (OSS portfolio). Requires a working build.
Verify everything here against current upstream
docs/before acting. Contribution process changes, and a stale instruction wastes a reviewer's time — which is the one cost that matters in an open-source contribution.
1. Why a Principal Engineer needs this
Landing a change in Chromium is a credential, but the reason it belongs in this track is narrower and better: it forces every other skill to be real. You cannot land a fix without locating the subsystem, understanding the invariant, writing the right test, and defending the design to someone who owns the code. Reading Blink is unfalsifiable; a CL is not.
It also teaches something you cannot learn from your own codebase: how to make a change in a system you do not own, for reviewers who owe you nothing. That skill transfers directly to cross-org work at Principal level.
2. Mental Model
2.1 The pipeline
find a bug -> reproduce -> locate subsystem -> minimal failing test
-> fix -> local tests -> git cl upload -> Gerrit review
-> OWNERS approval -> presubmit + try jobs -> CQ -> landed
Facts that shape the work:
- Issue tracker:
issues.chromium.org. (Chromium's owndocs/contributing.mdstill contains abugs.chromium.orgreference — treat in-tree docs as authoritative but not infallible, and prefer what the live site does.) - CLA required; first-time contributors add themselves to
AUTHORS. - Review happens in Gerrit (
chromium-review.googlesource.com), not GitHub PRs. One change = one CL, revised as patchsets, not as new commits. - OWNERS approval is required per affected directory.
git cl ownerssuggests reviewers. Committers need oneCode-Review +1; non-committers need two. - Presubmit runs on upload; try jobs compile and test across platforms. A CQ dry run is how you check before asking for a human's time.
2.2 Choosing the change
The ladder from the specification, with what each actually teaches:
| Rung | Change | Teaches |
|---|---|---|
| 0 | Build Chromium | toolchain, targets, iteration |
| 1 | Docs or test-only | the process end to end, at low risk |
| 2 | Small isolated correctness fix | locating a cause; minimal reproduction |
| 3 | Blink behaviour bug + regression test | spec → test → implementation, the core loop |
| 4 | Small rendering/style/layout improvement | subsystem depth, performance argument |
| 5 | Cross-component change | Mojo boundaries, multiple OWNERS, design review |
Do rung 1 before rung 2, even though it feels trivial. The first CL's difficulty is entirely
process — CLA, git cl, Gerrit conventions, presubmit, try-job failures unrelated to your
change. Learning that with a doc fix costs a day; learning it while also defending a behaviour
change costs a week and a reviewer's patience.
2.3 Where to find work
TestExpectations(bi-13) — documented, accepted, currently-wrong behaviours with bugs attached. This is the best-quality source of rung-3 candidates in the tree.- Failing WPTs in a subsystem you have studied.
- The issue tracker, filtered to components you know. Look for hotlists aimed at new contributors; verify the current label names on the live tracker rather than trusting any written list, including this one.
- A bug you actually hit. The strongest motivation and the best reproduction.
Choose a bug in a subsystem you have already studied in this track. A contribution is not the place to learn the subsystem.
2.4 What reviewers actually check
In rough order:
- Is the behaviour correct per the specification?
- Is there a test that fails without the fix?
- Is it at the right layer, and does it fit the subsystem's design?
- Ownership/lifetime correctness (
bi-06). - Style, naming, and
git cl format. - Does it need a flag, a metric, or a spec discussion first?
Item 6 catches people out: a behaviour change visible to the web may need a launch process, metrics, and standards-body agreement — not because Chromium is bureaucratic, but because unilateral behaviour changes break sites and interop. If your fix changes what the web sees, expect the conversation to be about compatibility, not correctness.
3. Practice
Verify against your checkout's docs/contributing.md and the linked process docs. The
mechanical parts (git cl upload, git cl format, git cl owners, CQ dry run) are stable;
the surrounding policy is not.
Keep a record per attempt — the specification asks for exactly this, and it is what turns a contribution into learning:
bug · reproduction · spec · suspected subsystem · source path · call path
· test · proposed fix · reviewer feedback · architectural lesson
3.5 Deep dive: the web-visible change process
Rung 3 and above frequently touch behaviour the web can observe. That is a different process from a bug fix, and not knowing it is the fastest way to have a technically-correct CL stall for months.
The shape of it:
idea -> spec discussion (WHATWG/W3C issue, or a explainer)
-> design doc, if non-trivial
-> UseCounter metrics: how much of the web actually does this?
-> intent-to-prototype -> behind a flag -> origin trial (sometimes)
-> intent-to-experiment / intent-to-ship on blink-dev
-> API owners' approval
-> ship, with metrics watching for regressions
The single most important artefact in that list is UseCounter. Blink instruments feature
usage and aggregates it across the web, so questions like "how many page loads use this quirk?"
have a real number attached. A removal proposal without usage data will not proceed.
This is the part that most surprises engineers arriving from product work. In a product you change behaviour and watch your own metrics. Here, "correct per spec" is necessary and not sufficient — you must also show the web will survive it. Compatibility is a constraint of equal weight to correctness, and arguing otherwise marks you as someone who has not internalised the problem.
If your fix changes what pages observe, expect the review conversation to be about compatibility and data, not about whether you read the spec correctly.
3.6 Deep dive: what makes a CL easy to approve
Reviewers are rationing attention across many changes. Optimise for their time, not yours.
Structural:
- One change per CL. A fix plus a refactor plus a rename is three CLs.
- Small. A first CL over ~200 lines is asking a stranger for a large favour.
- Test first in the description: state what fails without the fix.
git cl formatbefore every upload; never spend credibility on whitespace.
In the description:
- What the bug is, in one sentence a non-expert can follow.
- Why this layer is the right place to fix it — pre-empting the most likely objection.
- What you considered and rejected. This converts "why didn't you just…" into "they already thought about it."
Bug:footer, always.
In the code:
- Match the newest pattern in the file, not the nearest (
bi-06: migrations in progress). - Add a
DCHECKstating any new invariant. - Correct handle types (
Membervsraw_ptrvsunique_ptr) — the most likely substantive comment.
Handling review feedback
- Reply to every comment, even if only "Done."
- If you disagree, say so once, with reasoning, and ask a question rather than restating.
- If a reviewer wants a design change you think is wrong, ask what failure mode they are protecting against. Usually they know something you do not; occasionally the question reveals they misread. Either outcome is progress.
- Going quiet is worse than being wrong. An abandoned CL costs the reviewer more than a bad one.
3.7 Deep dive: how to pick a first bug that will actually land
Bad first bugs share a shape: they are interesting. Interesting bugs are unfixed because they are hard, contested, or blocked on a design decision.
A good first bug:
- is in a subsystem you have already studied in this track,
- has a reliable reproduction,
- has a clear expected behaviour, ideally spec-defined or in
TestExpectations, - is small — one file, one behaviour,
- is not load-bearing for a feature someone is actively rewriting (check
git logfor recent churn in the directory — heavy recent activity means you will conflict with a bigger change).
That last check takes thirty seconds and saves weeks:
git log --since=90.days --oneline -- <directory> | wc -l
A directory with a hundred commits in ninety days is being actively rewritten. Pick elsewhere for your first CL.
3.8 Deep dive: the record to keep, and why
The specification asks for a record per contribution. Here is why each field earns its place:
| Field | Why |
|---|---|
| bug | the problem, as the project sees it |
| reproduction | the thing you will lose first if you do not write it down |
| spec | what should happen, independent of any implementation |
| suspected subsystem | your prediction — score it later (bi-01 discipline) |
| source path + call path | the navigation, so it transfers |
| test | what would have caught this |
| proposed fix | including alternatives rejected |
| reviewer feedback | the highest-value field |
| architectural lesson | what you now believe that you did not before |
Reviewer feedback is the field to protect. It is the only part of this you cannot generate yourself: a domain expert telling you what you missed, for free, on your own work. Most engineers read it, fix the code, and forget it. Writing it down converts a code review into a durable lesson.
And write the record for rejected CLs too. A rejected CL with a clear architectural lesson is a successful lab; the goal of rungs 1–3 is competence, not a merge count.
4. Anti-Patterns
A first CL that is large. Reviewers ration attention; so should you.
Fixing a symptom at a call site because the real cause is in unfamiliar code.
Arguing with a reviewer about style. Run git cl format and spend your credibility on
substance.
Changing web-visible behaviour without checking compatibility. Expect to be asked for usage metrics and interop evidence.
Going quiet after review feedback. An abandoned CL costs the reviewer more than a bad one.
Starting at rung 3 to skip the boring parts. The boring parts are where the process failures live.
5. Trade-offs
Small safe changes vs meaningful ones. Rung 1 teaches process and nothing else. Rung 3 teaches the subsystem and risks stalling. Do both, in order.
Fixing vs filing. A well-written bug with a minimal reproduction is a real contribution and sometimes the better one, especially when the fix requires design agreement you cannot yet obtain.
Chromium vs WPT. A WPT contribution needs no C++, improves every browser, and lands faster. For an application engineer it is frequently higher leverage — and it is the right rung-1 alternative if a doc fix feels too trivial.
6. Lab
- Rung 0 — a build that runs. (Blocked here; see the roadmap's build guide §2.0.)
- Rung 1 — land a docs or test-only change. Goal: complete the process once. Record every step that surprised you.
- Rung 2 — from your
bi-13candidate list, pick the smallest defensible correctness fix. Write the failing test first. - Rung 3 — a Blink behaviour bug with a regression test, in a subsystem you studied.
- Maintain the record above for each, and write the architectural lesson even when the CL is rejected. A rejected CL with a clear lesson is a successful lab.
7. References
docs/contributing.mdin your checkout — the authority.docs/cl_tips.md,docs/code_reviews.md, and theOWNERSdocumentation.issues.chromium.org— the live tracker.- The Chromium blink-dev process for web-visible behaviour changes (intent-to-ship and friends).
- web-platform-tests contribution guide.
8. Principal Engineer Review
-
Your fix is correct per spec but would break a measurable fraction of sites. What happens next, and what is your role in it?
-
A reviewer asks for a design change that doubles the work and you think it is wrong. How do you handle it, and what would change your mind?
-
Argue that a well-written bug report is more valuable than a mediocre fix. Give the case where it is not.
-
Chromium requires OWNERS approval per directory. Argue this scales; then name its failure mode and what you would do as an owner to mitigate it.
-
You have one week of a team's time for open-source contribution. Chromium, WPT, or a framework? Justify from leverage, not from prestige.
-
Your CL sits unreviewed for three weeks. Enumerate your options in order of escalation, and say which you would actually use.
-
What makes a change "cross-component," and why is that qualitatively harder than a large change within one component?
-
You are onboarding an engineer to contribute upstream. Design their first month. What do you deliberately not let them do yet?