opsinjs
HandbookContributing

Contributing

How a change gets into opsinjs. The four routes in, what each one has to clear, and the one thing that will get a component proposal rejected fastest.

The short version

Four kinds of change, four different bars:

ChangeBarWhere
A documentation fixCorrectness. Open a pull request.Any page's "Edit this page"
A token changeA migration story, because a token is a public APIContributing tokens
A new componentA proposal answering the intake questions firstProposing a component
A change to doctrineA dated rationale and a named reviewerHealth

The fastest way to have a component proposal rejected is to open it with an API. The intake questions are about what the component asserts about somebody's health and what happens when it is wrong; a prop table does not answer either.

How it works

The three release phases

Every component arrives the same way:

plannedshippeddeprecated

  • planned is a full specification page: intent, when not to use it naming the alternative, the clinical contract, the proposed anatomy, the proposed API and the accessibility bar. Still no code. No id sits at planned today, because every catalogue row is implemented and installable.
  • shipped means code exists, it installs, and the API may change in any release. Every component has been audited against WCAG 2.2 AA by its own authors, in a static source pass and a rendered pass, so it is audited but not independently reviewed, and no component has had a clinical review. shipped means the source installs and the authors audited it, and it does not mean an independent reviewer or a clinician signed it. Nothing here is for a production health surface until a clinician signs it. See ADR 0025.
  • deprecated means the code still installs, a replacement is named, and a removal version is named.

What each phase promises is set out in Release phases. The important consequence for a contributor is that the specification is the deliverable at planned, and it is reviewed as seriously as code.

Review

Every change needs one review. Some need more:

  • Anything under health/ needs a clinical reviewer, and a reviewed date.
  • Anything that changes a colour token or a contrast pair means the generated contrast report must be regenerated and committed.
  • Anything user-visible in a component needs an accessibility review, recorded by setting reviewed and reviewer: design on the day it happened.
  • Any wording that appears on screen needs a content review.

One pair of frontmatter fields carries all four, reviewed and reviewer, which is what makes Docs freshness able to report expiry rather than guess at it. There is no second date field: a review is a review whoever signed it.

Generated files

A large share of this site is generated. If your change touches a token, a type, a keyboard table, a data attribute or the catalogue, the generated output must be regenerated and committed in the same change. CI runs the generators and fails on any diff. See ADR 0006.

Do this

  • Open an issue before a large change. A rejected component proposal after two weeks of work is a bad outcome for everybody, and the intake questions can be answered in an hour.
  • Read the page kind's template first. The outline is a contract that assert-ia enforces, and writing to the template is faster than writing prose and re-cutting it. See Documentation templates.
  • Say when something is your opinion. evidence: opinion is always preferred to a citation that does not quite say what you needed it to.
  • Run pnpm run check before opening the pull request. Four checks, in order: check:generated regenerates and fails on a diff, check:ia asserts the frontmatter, the section outlines and both link directions, check:a11y reads the component sources for a status carried by colour alone and the rest of the static accessibility rig, and check:llms proves the machine-readable surface. Freshness is not in it. pnpm run check:freshness is separate, and it reports rather than fails.
  • Keep the change one thing. A token rename and a new component in one pull request cannot be reviewed by the people who need to review each.

Not this

  • Never invent a citation, a statistic, a DOI or a date. This is the one rule with no exception. A fabricated reference in a health document is the worst thing this repository could contain, and it is worse than an honest absence.
  • Do not copy NHS or other Crown-copyright text. Cite it; write your own. See Licence and attribution.
  • Do not add a component because a competitor has one. A recorded decision not to build something is a real outcome, and saying so in a proposal costs nothing.
  • Do not hand-edit a generated file. It will be overwritten and the diff will fail CI.
  • Do not add a page without a kind, or a component page without a status. The build will reject either, and the rejection is deliberate.

Gotchas

  • assert-ia checks headings against the page kind. An extra H2 fails the build even if it is a good heading, because the outline is what keeps hundreds of pages navigable.
  • Aliases are globally unique. They are declared in registry/catalogue.ts; a page that invents one will collide eventually.
  • Links in MDX are relative and resolved by createRelativeLink. An absolute site link fails the IA check, and there is no longer an exception.
  • British spelling in prose, American in code. A page named colour-independence.mdx documenting a ColorScale is correct. See Naming conventions.
  • A clean clone needs pnpm install before typecheck, because .source/ is generated by postinstall and gitignored.

On this page