---
title: "Changelog"
description: "What actually shipped in each release, written as prose, with the breaking parts at the top."
url: "https://opsinjs.pensievelabs.org/project/changelog"
source: "https://opsinjs.pensievelabs.org/project/changelog.md"
section: "Project"
kind: "project"
reviewed: "2026-09-20"
reviewer: "engineering"
aliases: ["releases", "what changed", "release notes"]
---

> Elements written as `<PascalCase … />` below are opsinjs documentation
> components. Their attributes are the content: the values they render are
> generated from `tokens/*.json` and `registry/catalogue.ts` and are
> published separately at https://opsinjs.pensievelabs.org/r/index.json and under the Reference
> section.
> Nothing is missing from this page. The data simply does not live in
> the prose.

<PageTemplate kind="project" />

## Releases [#releases]

* [0.0.0. The scaffold](./2026-09-scaffold.mdx) · 2 September 2026

There is one entry, and it describes a documentation site with no components in
it. [State of the system](../state-of-the-system.mdx) is the page that says what
that means in practice.

<Todo>
  Sixty components were built after 0.0.0 and no entry on this page records them.
  Until one is written, this
  changelog understates what the project contains and State of the system is the
  page to read instead. Writing the entry needs a version number to file it under,
  and every catalogue row is still `since: unreleased`. The number is therefore the
  decision blocking it, not the prose.
</Todo>

A feed of these entries is published at `/rss.xml`.

## How entries are written [#how-entries-are-written]

**One file per release, named by date**, so the newest is always first without
anybody maintaining an order.

**Breaking changes first.** Not in a section at the bottom labelled "notes". If a
release changes something you have already built against, that is the first thing
on the page, and it names the version that introduced the change and what to do
about it.

**Prose, not commit subjects.** A list of merged pull-request titles is a record
of what the maintainers did. An entry is a description of what changed for the
person reading it, which is a different document and takes longer to write.

**Every entry says what did not change**, where that is the interesting part.
That matters particularly for the surfaces the
[versioning policy](../versioning-policy.mdx) covers beyond the JavaScript API:
the rendered DOM, the `data-*` attributes and the CSS custom properties.

**A changed clinical default leads the entry, on its own line, labelled
`SAFETY`.** Not in a bullet list with the refactors, and not below the fold. The
change this rule is about is a presentation change: a status word, a default
rounding or unit, a colour pairing, an aria announcement, or the wording of an
uncertainty or staleness note. opsinjs owns no clinical threshold and an entry
must never read as though it does. What it owns is how a value someone else
decided is shown to a patient, and changing that changes what a person believes
about their own health. This is a rule rather than a convention because of how
the code is distributed. A consumer who copied the file does not receive the
change when it ships. They receive it when they next copy the file, which may
be never. The entry is the only thing that can tell them a safety change is
sitting upstream waiting.

## What belongs somewhere else [#what-belongs-somewhere-else]

**A deprecation** appears here when it happens and lives on
[Deprecations](../deprecations.mdx) until it is removed, so that the current list
is one page rather than an archaeology exercise across entries.

**A change needing more than a paragraph to migrate through** gets a written
guide, linked from the entry. The
[versioning policy](../versioning-policy.mdx) says which four kinds of change
earn one. Entries stay readable; guides get as long as they need to be.

**The reasoning behind a change**, where it is architectural, belongs in a
[decision record](../decisions/index.mdx). An entry says what changed; a record
says why, and survives being read three years later.

<LastUpdated />

<Reviewed />
