refactor(release-notes): give every release a number and a commit

The version strings are dates ("2026.11.01"), so a release has no
identity that is not a date. Every entry now also carries a release
number and the short SHA of the commit it went out with.

The date-shaped version string is left in place for now — the popup
switches over and drops it in the next commit, so this one stays
green on its own.

A test holds the numbering unique, contiguous and newest-first, and
holds every commit to a real SHA.
This commit is contained in:
Dave 2026-11-02 20:35:57 +02:00
parent a0e02759d2
commit fd5bb11325
2 changed files with 56 additions and 2 deletions

View file

@ -0,0 +1,34 @@
import { describe, expect, it } from "vitest";
import { LATEST_RELEASE, RELEASE_NOTES } from "./release-notes";
describe("the release-note registry", () => {
it("numbers the releases 1..N with no gaps and no duplicates", () => {
const numbers = RELEASE_NOTES.map((r) => r.release);
expect(new Set(numbers).size).toBe(numbers.length);
expect([...numbers].sort((a, b) => a - b)).toEqual(
Array.from({ length: RELEASE_NOTES.length }, (_, i) => i + 1)
);
});
it("keeps the newest release at the top of the list", () => {
const numbers = RELEASE_NOTES.map((r) => r.release);
expect(numbers).toEqual([...numbers].sort((a, b) => b - a));
expect(LATEST_RELEASE).toBe(RELEASE_NOTES[0]);
});
it("gives every release a commit SHA", () => {
for (const release of RELEASE_NOTES) {
expect(release.commit).toMatch(/^[0-9a-f]{7,40}$/);
}
});
it("gives every release a headline and at least one item", () => {
for (const release of RELEASE_NOTES) {
expect(release.title.length).toBeGreaterThan(0);
expect(release.items.length).toBeGreaterThan(0);
}
});
});

View file

@ -13,9 +13,19 @@
*/
export interface ReleaseNote {
/** Version marker. Bump this to re-notify operators. */
/** Version marker. Bumped to re-notify operators. */
version: string;
/** ISO date (YYYY-MM-DD) of the release. */
/**
* Release number. 1 = the first release. This replaces the date-shaped
* `version` string and becomes the "seen" marker.
*/
release: number;
/** Short SHA of the commit this release went out with. */
commit: string;
/**
* Authoring reference only — the day the release was written up.
* Deliberately never rendered: the popup carries no dates.
*/
date: string;
/** One-line headline for the release. */
title: string;
@ -26,6 +36,8 @@ export interface ReleaseNote {
export const RELEASE_NOTES: ReleaseNote[] = [
{
version: "2026.11.01",
release: 5,
commit: "139ea25",
date: "2026-11-01",
title: "Delivery Pool, letterhead lock and a dark mode section",
items: [
@ -38,6 +50,8 @@ export const RELEASE_NOTES: ReleaseNote[] = [
},
{
version: "2026.10.30",
release: 4,
commit: "83aec14",
date: "2026-10-30",
title: "Collection Confirm gets a second pair of eyes",
items: [
@ -49,6 +63,8 @@ export const RELEASE_NOTES: ReleaseNote[] = [
},
{
version: "2026.10.28",
release: 3,
commit: "3eea87e",
date: "2026-10-28",
title: "Auto-push and a shortcut to AI settings",
items: [
@ -58,6 +74,8 @@ export const RELEASE_NOTES: ReleaseNote[] = [
},
{
version: "2026.10.26",
release: 2,
commit: "b212d0f",
date: "2026-10-26",
title: "A phone board for the managers",
items: [
@ -67,6 +85,8 @@ export const RELEASE_NOTES: ReleaseNote[] = [
},
{
version: "2026.10.24",
release: 1,
commit: "55cc7fa",
date: "2026-10-24",
title: "One POS matcher, AI-only quote matching",
items: [