Four surfaces, one version number
A pin protects a site from package changes only. The API and database move under every site instantly, which is why the compatibility rule exists.
The two standing rules
1
API and database changes are additive and backward-compatible
After any rollback an old package talks to the newest API and schema, so the newest must keep working for the oldest pinned version in the fleet.
2
Release small and often
A big batched release destroys rollback granularity: rolling back past a two-week batch loses two weeks of fixes, not one day’s.
Expand, migrate, contract
- Expand freely: tables, nullable or defaulted columns, new routes, optional parameters, new response fields. Old clients ignore what they do not know.
- Migrate: release the package version that uses the new thing; roll sites forward.
- Contract only in a breaking release, and only once every site is at or above the version that stopped depending on the old shape.
The release flow
- A change to the packages carries a changeset. Its first paragraph is the changelog post.
- Merging to main ships nothing. A “Version Packages” pull request accumulates pending changesets.
- Merging that pull request publishes. Nothing deploys to any site.
- Each site adopts a version deliberately: a bump pull request in its own repository, or an explicit version move for a rollback. Merging it is that site’s go-live.
0.x, a minor bump means breaking and a patch means everything else. A breaking changeset carries its migration note right then.