From 6e00924928c7548bb7a008a9323467be664cf24b Mon Sep 17 00:00:00 2001 From: Lucas Carlson Date: Sun, 18 Oct 2026 08:30:09 -0700 Subject: [PATCH 1/3] docs: add a maintenance and continuity page A reader who checks maturity asks who maintains the package, how a release is published, and what they keep if maintenance stops. One page now answers these questions and asks for more maintainers. The README, the versioning page, and the comparison pages link to the new page and no longer state a count of maintainers. A new test fails when a page states one. --- README.md | 3 +- docs/compare/dbos.md | 2 +- docs/compare/graphile-worker.md | 2 +- docs/compare/restate.md | 2 +- docs/compare/rivetkit.md | 2 +- docs/maintenance.md | 70 +++++++++++++++++++++++++++++++++ docs/versioning.md | 4 +- test/maintenance-guide.test.ts | 37 +++++++++++++++++ 8 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 docs/maintenance.md create mode 100644 test/maintenance-guide.test.ts diff --git a/README.md b/README.md index c948db9..855bf50 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ explains the model and when to use it. **Status.** Version 1.0: the public API follows semantic versioning and does not break before 2.0. [Versioning](docs/versioning.md) gives the limits of the -promise. First public release: August 13, 2026. One maintainer. +promise. First public release: August 13, 2026. **Production use.** One first-party application with more than 100,000 users runs it in production. That is a count of users, not a measure of load. No @@ -294,6 +294,7 @@ then shows a tested Solid Objects version with its limits: - [Operations and recovery](docs/operations.md) - [Observability and diagnostics](docs/observability.md) - [Detailed architecture](docs/architecture.md) +- [Maintenance and continuity](docs/maintenance.md) - [Detailed documentation](docs/) The benchmarks, parity ledger, dashboard, browser setup, and exhaustive API diff --git a/docs/compare/dbos.md b/docs/compare/dbos.md index 8b2f2b1..0d1b7c7 100644 --- a/docs/compare/dbos.md +++ b/docs/compare/dbos.md @@ -353,7 +353,7 @@ How it works: - First public release of the npm package: August 13, 2026. - Version 1.0.0: October 13, 2026. The public API follows [semantic versioning](../versioning.md). -- One maintainer. +- [Maintenance and continuity](../maintenance.md) tells you who maintains the project and how a release is made. - One first-party application with more than 100,000 users runs it in production. That is a count of users, not a measure of load. No production use by other people is known. - The [benchmarks](../benchmarks.md) are development measurements. Longer soak tests are open work. diff --git a/docs/compare/graphile-worker.md b/docs/compare/graphile-worker.md index 90a5b95..be8c181 100644 --- a/docs/compare/graphile-worker.md +++ b/docs/compare/graphile-worker.md @@ -258,7 +258,7 @@ How it works: - First public release of the npm package: August 13, 2026. - Version 1.0.0: October 13, 2026. The public API follows [semantic versioning](../versioning.md). -- One maintainer. +- [Maintenance and continuity](../maintenance.md) tells you who maintains the project and how a release is made. - One first-party application with more than 100,000 users runs it in production. That is a count of users, not a measure of load. No production use by other people is known. - The [benchmarks](../benchmarks.md) are development measurements. Longer soak tests are open work. diff --git a/docs/compare/restate.md b/docs/compare/restate.md index a36e3b8..6d2fb52 100644 --- a/docs/compare/restate.md +++ b/docs/compare/restate.md @@ -254,7 +254,7 @@ A model call can run again after a crash, because effects run at least once. If - First public release of the npm package: August 13, 2026. - Version 1.0.0: October 13, 2026. The public API follows [semantic versioning](../versioning.md). -- One maintainer. +- [Maintenance and continuity](../maintenance.md) tells you who maintains the project and how a release is made. - One first-party application with more than 100,000 users runs it in production. That is a count of users, not a measure of load. No production use by other people is known. - The [benchmarks](../benchmarks.md) are development measurements. Longer soak tests are open work. diff --git a/docs/compare/rivetkit.md b/docs/compare/rivetkit.md index b66cd4b..2dcb68e 100644 --- a/docs/compare/rivetkit.md +++ b/docs/compare/rivetkit.md @@ -246,7 +246,7 @@ How it works: - First public release of the npm package: August 13, 2026. - Version 1.0.0: October 13, 2026. The public API follows [semantic versioning](../versioning.md). -- One maintainer. +- [Maintenance and continuity](../maintenance.md) tells you who maintains the project and how a release is made. - One first-party application with more than 100,000 users runs it in production. That is a count of users, not a measure of load. No production use by other people is known. - The [benchmarks](../benchmarks.md) are development measurements. Longer soak tests are open work. diff --git a/docs/maintenance.md b/docs/maintenance.md new file mode 100644 index 0000000..d51b604 --- /dev/null +++ b/docs/maintenance.md @@ -0,0 +1,70 @@ +# Maintenance and continuity + +This page tells you who maintains Solid Objects, how a release is made, and +what you keep if maintenance stops. It also tells you how to help maintain the +project. + +## Who maintains it + +Lucas Carlson ([@cardmagic](https://github.com/cardmagic)) is the lead +maintainer of the npm package `solid-objects` and of the Ruby gem +[`solid_objects`](https://github.com/cardmagic/solid-objects-ruby). The two +packages use the same model and the same correctness contract. A change to the +model goes into both packages, and the [parity ledger](parity.md) records each +difference between them. + +The same maintainer sells [Solid Objects Pro](https://solidobjects.pro), a +commercial package that batches operations at scale. Pro depends on this +package. This package does not depend on Pro, and it needs no account, license +key, or service from the maintainer. + +## How a change is checked + +CI runs on each push and each pull request: + +- Types, formatting, documentation links, the unit tests with coverage, and + the packaged artifact. +- The suite on the oldest supported Node.js version. +- The database suites on PostgreSQL and MySQL, and the Redis wake-up suite. +- The browser runtime in Chromium. + +[Supported versions](support.md) lists the CI matrix. The +[correctness contract](correctness.md) lists the guarantees that the tests +check. + +## How a release is made + +1. The maintainer pushes a version tag, for example `v1.0.3`. +2. GitHub Actions runs all test jobs again on that tag. +3. If all test jobs pass, GitHub Actions publishes the package to npm with + trusted publishing. The repository keeps no npm token, and npm shows a + provenance attestation for each version. +4. The same job makes a GitHub release from the changelog. + +[Releasing](releasing.md) gives the full procedure. [Versioning](versioning.md) +tells you what a release can change. [CHANGELOG.md](../CHANGELOG.md) lists each +release. + +## What you keep if maintenance stops + +- **Your data.** With the SQL runtime, actor state, mailboxes, reminders, and + effects are rows in your application's database. No service of the + maintainer holds your data. +- **The code.** The [MIT License](../MIT-LICENSE) lets anyone use, change, + fork, and publish the code. +- **The checks.** The tests and the CI configuration are in this repository. A + fork can check its changes with the same suite. + +## Help maintain Solid Objects + +The project wants more maintainers. Experience with TypeScript and Node.js, +with locks and transactions in PostgreSQL or MySQL, or with Rails helps. + +1. Read [CONTRIBUTING.md](../CONTRIBUTING.md). +2. Send a small pull request: a fix, a test, or a correction to a guide. +3. After some of your pull requests are merged, open an + [issue](https://github.com/cardmagic/solid-objects-js/issues) to ask to + become a maintainer. + +To report a vulnerability, use the private process in +[SECURITY.md](../SECURITY.md). diff --git a/docs/versioning.md b/docs/versioning.md index 1898a46..d0d3e07 100644 --- a/docs/versioning.md +++ b/docs/versioning.md @@ -41,8 +41,8 @@ change. A patch release does not raise a minimum version. Version 1.0 is a promise about the API. It is not a claim of measured scale. The [benchmarks](benchmarks.md) are development measurements and do not -guarantee capacity. Longer soak tests are open work. The project has one -maintainer, and no production use by other people is known. +guarantee capacity. Longer soak tests are open work. No production use by +other people is known. ## Releases before 1.0 diff --git a/test/maintenance-guide.test.ts b/test/maintenance-guide.test.ts new file mode 100644 index 0000000..d410dbf --- /dev/null +++ b/test/maintenance-guide.test.ts @@ -0,0 +1,37 @@ +import { existsSync, readdirSync, readFileSync } from "node:fs" +import { describe, expect, it } from "vitest" + +const root = new URL("../", import.meta.url) +const maintainerCount = /\b(?:one|only|sole|single)\s+maintainer\b/i +const documentationPaths = [ + "README.md", + "CONTRIBUTING.md", + "SECURITY.md", + ...readdirSync(new URL("docs/", root), { encoding: "utf8", recursive: true }) + .filter((path) => path.endsWith(".md")) + .sort() + .map((path) => `docs/${path}`), +] + +function read(path: string): string { + return existsSync(new URL(path, root)) ? readFileSync(new URL(path, root), "utf8") : "" +} + +describe("maintenance guide", () => { + it("is linked from the README", () => { + expect(read("README.md")).toContain("(docs/maintenance.md)") + }) + + it("names the lead maintainer", () => { + expect(read("docs/maintenance.md")).toMatch(/is the lead\s+maintainer/) + }) + + it("has no page in the documentation that states a count of maintainers", () => { + const pages = documentationPaths.filter((path) => maintainerCount.test(read(path))) + expect(pages).toEqual([]) + }) + + it("tells a contributor how to start", () => { + expect(read("docs/maintenance.md")).toContain("(../CONTRIBUTING.md)") + }) +}) From a38d087a485193476c0c2cc97adafb1429984c73 Mon Sep 17 00:00:00 2001 From: Lucas Carlson Date: Sun, 18 Oct 2026 08:30:10 -0700 Subject: [PATCH 2/3] chore: prepare version 1.0.3 --- CHANGELOG.md | 9 +++++++++ package.json | 2 +- src/version.ts | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95a2991..669fde0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.0.3 - 2026-10-18 + +- Add `docs/maintenance.md`. It tells you who maintains the package, how CI + checks each change, how a release is published, what you keep if + maintenance stops, and how to become a maintainer. The README, + `docs/versioning.md`, and the comparison pages now link to this page and no + longer state a count of maintainers. A new test fails when a page states + one. + ## 1.0.2 - 2026-10-15 - Add four comparison pages in `docs/compare/`: Restate virtual objects, DBOS diff --git a/package.json b/package.json index 6b045ea..a4e8edf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "solid-objects", - "version": "1.0.2", + "version": "1.0.3", "description": "Fix race conditions across Node.js processes: ordered operations, expiring holds, and state that survives a restart, in your SQL database. A SQL-backed virtual actor library for TypeScript and Node.js.", "type": "module", "license": "MIT", diff --git a/src/version.ts b/src/version.ts index d688532..44dcd98 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = "1.0.2" +export const VERSION = "1.0.3" From 09c56ecd04d402106823667b2820a52b99fe973b Mon Sep 17 00:00:00 2001 From: Lucas Carlson Date: Sun, 18 Oct 2026 08:46:09 -0700 Subject: [PATCH 3/3] test: catch each form of a maintainer count The count pattern now finds numerals and plural forms, and a test checks the pattern against examples. The maintenance page test now checks the name and profile link of the lead maintainer. The changelog no longer says that the versioning page links to the maintenance page. --- CHANGELOG.md | 4 ++-- test/maintenance-guide.test.ts | 21 +++++++++++++++++++-- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 669fde0..4b273fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,8 @@ - Add `docs/maintenance.md`. It tells you who maintains the package, how CI checks each change, how a release is published, what you keep if - maintenance stops, and how to become a maintainer. The README, - `docs/versioning.md`, and the comparison pages now link to this page and no + maintenance stops, and how to become a maintainer. The README and the + comparison pages now link to this page. They and `docs/versioning.md` no longer state a count of maintainers. A new test fails when a page states one. diff --git a/test/maintenance-guide.test.ts b/test/maintenance-guide.test.ts index d410dbf..9a2522f 100644 --- a/test/maintenance-guide.test.ts +++ b/test/maintenance-guide.test.ts @@ -2,7 +2,8 @@ import { existsSync, readdirSync, readFileSync } from "node:fs" import { describe, expect, it } from "vitest" const root = new URL("../", import.meta.url) -const maintainerCount = /\b(?:one|only|sole|single)\s+maintainer\b/i +const maintainerCount = + /\b(?:\d+|one|two|three|four|five|six|seven|eight|nine|ten|only|sole|single)\s+maintainers?\b/i const documentationPaths = [ "README.md", "CONTRIBUTING.md", @@ -23,7 +24,23 @@ describe("maintenance guide", () => { }) it("names the lead maintainer", () => { - expect(read("docs/maintenance.md")).toMatch(/is the lead\s+maintainer/) + expect(read("docs/maintenance.md")).toMatch( + /Lucas Carlson \(\[@cardmagic\]\(https:\/\/github\.com\/cardmagic\)\) is the lead\s+maintainer/, + ) + }) + + it("has a count pattern that finds a count of maintainers in each form", () => { + for (const text of [ + "One maintainer.", + "1 maintainer", + "two maintainers", + "the only\nmaintainer", + ]) { + expect(text).toMatch(maintainerCount) + } + for (const text of ["the lead maintainer", "wants more maintainers", "become a maintainer"]) { + expect(text).not.toMatch(maintainerCount) + } }) it("has no page in the documentation that states a count of maintainers", () => {