# Design Decisions

This directory is the log of design decisions that apply across the Selenium project —
one file per decision, numbered by the pull request that proposes it.

Selenium ships the same API in multiple languages. Decisions about user-visible behavior,
API shape, and cross-binding semantics need to be made once, recorded, and implemented
consistently everywhere. This log is the canonical record of those decisions: when a
question comes up in review, the answer should be a link to a file here.

## What needs a decision record

- User-visible behavior that should be consistent across bindings: API naming and shape,
  error types and messages, default timeouts, capability handling
- WebDriver Classic / BiDi semantics and how the protocol is exposed (or deliberately not exposed)
- Deprecation and backwards-compatibility commitments
- Anything the TLC has labeled [`A-needs-decision`](https://github.com/SeleniumHQ/selenium/labels/A-needs-decision)
  and resolved

## What doesn't

- Single-binding internals (a Java maintainer picking a data structure)
- Build tooling and infrastructure choices
- Anything cheaply reversible

When in doubt, ask whether the question is likely to be raised again. If it is, record the decision.

## Scope: what belongs in one record

A record captures one coherent decision — which usually means a cluster of related sub-choices
that share the same context and rationale and are settled as a unit. Bundling those is correct,
not a flaw: a record on how clicks behave can settle scrolling, hit-testing, and pointer movement
together because they are one design with one rationale.

The test for splitting is **not** "could this part be adopted on its own?" — almost any part can.
Split only when a sub-choice has its own rationale that stands without the others, would be debated
and decided separately, or could later be reversed without disturbing the rest. If splitting would
force a reader to open several records to understand any one of them, they belong in the same record.

## Process

1. **Propose.** Anyone may propose: copy [0000-template.md](0000-template.md) to `short-title.md`,
   fill it in with `Status: Proposed`, and open a PR. Once GitHub assigns the PR number, rename the
   file to `NNNN-short-title.md` using that number, before merge. Keep it to about a page — if the
   debate already happened in an issue, the record can be short and link to it.

   Open the PR with the ADR pull-request template by appending `?expand=1&template=adr.md` to the
   compare URL — GitHub has no picker for PR templates, so this query parameter is the only way to
   select it (e.g. `https://github.com/SeleniumHQ/selenium/compare/trunk...your-branch?expand=1&template=adr.md`).
   Keep the PR body to review logistics; the decision and rationale belong in the record, not the PR.
2. **Discuss.** The PR thread is the discussion record. Decisions that need synchronous
   discussion are raised at a TLC meeting; the outcome goes back into the PR. Disagreement
   about the considered options is resolved by revising the document during review, so the
   merged record reflects the debate accurately. The TLC sets its meeting agenda; proposals
   advance as agenda time allows.
3. **Decide.** The Selenium Project Lead merges the record once the approval requirements
   below are met and discussion has run its course, with the status updated to `Accepted` —
   merging constitutes acceptance. Proposals the TLC considers and declines are merged as
   `Rejected`; proposals withdrawn or abandoned before TLC consideration are closed and the
   number lapses.
4. **Implement.** When a record is accepted, open an ADR tracking issue (use the
   [ADR Implementation Tracking](https://github.com/SeleniumHQ/selenium/issues/new?template=adr-tracking.yml) issue template) — one
   checkbox per binding, linking each implementing PR as it lands — and link the issue from the
   record's PR. Tracking lives in the issue, not the committed record, so the immutable file doesn't
   churn as bindings converge; updating the issue needs no TLC review.

## Approval

- TLC members respond to a proposal with a GitHub review: an approval, a "no objection"
  comment review (saw it, deferring to the others), or a request-changes review stating
  what would resolve it.
- Records are accepted by consensus: a majority of TLC members have responded, none with
  an unresolved objection. Before acceptance, a record must have been open at least one
  week and an agenda item at a TLC meeting — no one should learn of a decision after it
  is made.
- If substantive edits are made, the author re-requests reviews.
- An objection that revision cannot resolve — including support for a different considered
  option — is discussed at a TLC meeting. If consensus still fails, the Selenium Project
  Lead decides which position prevails; the record is updated to match, and overruled
  dissent is summarized rather than erased.

## Rules

- **A decision must stand alone.** A reader gets the decision, the rationale, and the rejected
  alternatives without following any links; linked material is background, not required reading.
- **A record fixes the decision and its rationale, not the implementation.** It says what every
  binding must do and why; how each binding builds it lives in the adopting PRs and code.
- **Accepted decisions are immutable**, except for the status line. Changing a decision means a
  new record that supersedes the old one — update the old record's status to `Superseded by [NNNN](...)`.
- **The number is the proposal's PR number.** It gets cited in reviews and issues and links
  straight to the discussion. Gaps in numbering are expected.
- **Durable supporting material goes in the record itself** (an Appendix section at the end).
  Ephemeral evidence and debate stay in the PR thread.
