Problem
The current maintainer-pushed v* tag is a valid release decision, but the decision is not represented as a reviewable repository change: the next version, changelog, release contents, and publication timing are only visible after the tag is pushed.
This issue is not proposing that CI publish every merge, build arbitrary HEAD snapshots, or create rolling tags. Ordinary pull requests should continue to merge without publishing anything.
There are two separate approvals:
- merging a feature/fix PR approves that code for main;
- cutting a release approves a specific batch of changes, version, changelog, and a set of irreversible registry writes.
The current workflow also creates the public GitHub Release before npm publication finishes. npm has no transaction across the six platform packages and the root package, so a later failure can leave a visible partial release. Existing-package recovery checks only that name@version exists; it does not verify that the published tarball is the artifact this workflow intended to publish.
Non-goals
- No automatic publication for every merge to main.
- No HEAD, nightly, or moving snapshot tag.
- No Git tag or changelog per platform package.
- No independently versioned platform packages.
- No attempt to roll back or overwrite an immutable npm version.
Proposed design
1. Keep one logical product and one version
Treat OpenCodeReview as one Go CLI release:
- one committed product version;
- one changelog;
- one vX.Y.Z Git tag;
- one GitHub Release;
- seven npm registry artifacts at the same exact version: six transport packages plus the root wrapper.
The six platform packages are implementation artifacts required by npm's platform-selection model, not separate release units.
2. Add an explicit release cut
Use Release Please only for the version/changelog PR layer, configured as one root Go/CLI release.
- Normal merges update or open the release PR; they do not publish.
- A maintainer merges the release PR when the accumulated changes are ready.
- That merge is the explicit release approval.
- Configure Release Please not to publish the GitHub Release itself; the custom release workflow should do that only after artifact publication and verification.
Release Please is proposed here because the repository already uses Conventional Commit titles and has one logical product. It does not replace the native build or npm publisher.
3. Keep a product-specific release coordinator
The release workflow should:
- Resolve the version once from the committed release state and validate strict SemVer.
- Build all six Go binaries from the exact release commit and inject the same version with ldflags.
- Generate checksums and provenance.
- Generate all six npm platform package directories from one canonical target manifest.
- Pack every npm tarball and validate filenames, os/cpu, embedded binary version, and root optionalDependencies before the first registry write.
- Publish platform packages first.
- Publish the root wrapper last.
- Install the exact published root version in clean Linux, macOS, and Windows jobs and run ocr version.
- Only after verification, create the single vX.Y.Z tag and public GitHub Release.
The effective public commit point is the root package: it must never become installable before all exact platform dependencies exist.
4. Make partial publication resumable
A retry for the same version must be safe:
- serialize releases with workflow concurrency and cancel-in-progress: false;
- for every existing name@version, compare registry integrity with the locally packed tarball;
- accept and skip only an identical artifact with the expected provenance;
- fail closed if the version exists with different contents;
- never delete or attempt to reuse an npm version;
- provide a manual workflow_dispatch recovery/dry-run entry that resumes the same release commit and version, rather than publishing an arbitrary branch head.
5. Reduce duplicated release metadata
Keep one machine-readable target list containing:
- Go OS/architecture;
- npm package name;
- npm os/cpu values;
- build artifact name;
- packaged binary filename.
The build matrix, npm package generator, checksum verifier, fallback downloader, and smoke tests should all consume or validate against that same list.
6. Use short-lived publication identity
Move npm publication to Trusted Publishing/OIDC with provenance, protected by the release environment. Avoid writing a long-lived NPM_TOKEN into the self-hosted runner's home directory.
Why not Changesets as the publisher?
Changesets is a good version-intent tool, but it does not build native targets, make seven npm publishes transactional, enforce platform-first/root-last order, or reconcile a partial registry failure.
A root-only Changesets setup would be possible, but it would add per-PR fragments without removing the need for the same custom publisher. For this repository's single-product Conventional Commit model, Release Please is the smaller version/changelog layer. The publication architecture above remains necessary whichever version tool is chosen.
Implementation sketch
- Add release-please-config.json and .release-please-manifest.json for one root release, with automatic GitHub Release creation disabled.
- Add a small release-PR workflow for version/changelog maintenance.
- Refactor .github/workflows/release.yml so the release-PR merge, not every ordinary merge, starts the coordinated publication.
- Replace the duplicated shell/workflow platform tables with one canonical target manifest and a generator/validator.
- Add tarball preflight, registry integrity reconciliation, root-last publication, post-publish install smoke tests, and a recovery dispatch.
- Keep the existing local publisher as a manual frontend to the same coordinator instead of maintaining a second release algorithm.
Acceptance criteria
- Ordinary merges never publish.
- A maintainer can review the exact version and changelog before release.
- One release creates exactly one product tag and one GitHub Release.
- All binaries and npm packages use the same version.
- Platform packages are published before the root wrapper.
- A partial npm failure can be resumed safely and rejects mismatched existing artifacts.
- The public GitHub Release is created only after exact-version installation succeeds.
- No long-lived npm token is required by the release job.
Large-project references
Problem
The current maintainer-pushed v* tag is a valid release decision, but the decision is not represented as a reviewable repository change: the next version, changelog, release contents, and publication timing are only visible after the tag is pushed.
This issue is not proposing that CI publish every merge, build arbitrary HEAD snapshots, or create rolling tags. Ordinary pull requests should continue to merge without publishing anything.
There are two separate approvals:
The current workflow also creates the public GitHub Release before npm publication finishes. npm has no transaction across the six platform packages and the root package, so a later failure can leave a visible partial release. Existing-package recovery checks only that name@version exists; it does not verify that the published tarball is the artifact this workflow intended to publish.
Non-goals
Proposed design
1. Keep one logical product and one version
Treat OpenCodeReview as one Go CLI release:
The six platform packages are implementation artifacts required by npm's platform-selection model, not separate release units.
2. Add an explicit release cut
Use Release Please only for the version/changelog PR layer, configured as one root Go/CLI release.
Release Please is proposed here because the repository already uses Conventional Commit titles and has one logical product. It does not replace the native build or npm publisher.
3. Keep a product-specific release coordinator
The release workflow should:
The effective public commit point is the root package: it must never become installable before all exact platform dependencies exist.
4. Make partial publication resumable
A retry for the same version must be safe:
5. Reduce duplicated release metadata
Keep one machine-readable target list containing:
The build matrix, npm package generator, checksum verifier, fallback downloader, and smoke tests should all consume or validate against that same list.
6. Use short-lived publication identity
Move npm publication to Trusted Publishing/OIDC with provenance, protected by the release environment. Avoid writing a long-lived NPM_TOKEN into the self-hosted runner's home directory.
Why not Changesets as the publisher?
Changesets is a good version-intent tool, but it does not build native targets, make seven npm publishes transactional, enforce platform-first/root-last order, or reconcile a partial registry failure.
A root-only Changesets setup would be possible, but it would add per-PR fragments without removing the need for the same custom publisher. For this repository's single-product Conventional Commit model, Release Please is the smaller version/changelog layer. The publication architecture above remains necessary whichever version tool is chosen.
Implementation sketch
Acceptance criteria
Large-project references