-
Notifications
You must be signed in to change notification settings - Fork 0
Canary Snapshots
Last synced from
docs/engineering/process/canary.mdon 2026-08-05. The repo file is the source of truth. If the two diverge, follow the repo.
This page describes canary snapshots, a future addition to the release pipeline
for @deessejs/fp. Canary snapshots are not implemented today — there is no
canary workflow, no canary Trusted Publisher slot, and no canary package on npm.
This page documents the design so that the concept is captured before it is forgotten.
Outline
- What is a canary snapshot
- Why we want canary snapshots
- Why we do not have canary snapshots today
- Target workflow
- Known limitations
- Migration to pkg.pr.new
- When to revisit this decision
- Related documents
A canary snapshot is a pre-release version of @deessejs/fp published from a pull
request, on every push to that PR. It is not a tagged release. It exists to let
reviewers and external users install a pre-merge build and exercise it in real
conditions before the PR lands.
The mechanism: every push to a PR produces a published package installable as
npm install @deessejs/fp@canary. The package name does not match semver but is
stable per PR.
In the wider npm ecosystem, this pattern goes by several names:
- Vercel calls it
pkg.pr.new. - Changesets calls it
snapshots, published under a dist-tag like@canary. - Some projects use custom names like
@nextor@experimental.
Three concrete benefits over the current PR-only review:
-
External testers can validate. A PR reviewer who is not a maintainer cannot
install the PR locally without setting up the dev environment. A canary snapshot
lets them run
npm install @deessejs/fp@canaryin their own project and report real-world issues. -
Integration tests against real consumers. If
@deessejs/fpis used by other packages, a canary snapshot lets those packages run their CI against the canary build and report regressions before the PR merges. -
Reviewers can test in their own stack. Today, a reviewer reads the diff and
maybe runs
pnpm testlocally. With canary, they can install in their project and see how the change behaves end-to-end.
The design is documented in the senior plan as a target architecture. The reason it is not implemented is operational, not conceptual:
-
Pollutes the public npm registry. Every push to a PR publishes a package
under the
@canarydist-tag. The package name does not match semver expectations. For a project that values release hygiene (see Release Process § Goal: every merge tomainis a release), this is a high price to pay. -
Concurrent PRs overwrite each other. Two PRs open in parallel both publish
to
@canary. Whichever publishes last wins; the earlier snapshot is no longer installable. There is no stable identifier per PR without additional tooling. -
Requires a separate Trusted Publisher slot on npm. The current Trusted
Publisher is registered for
publish.yml. A canary workflow cannot reuse that slot without compromising thereleaseenvironment protection. -
Single-maintainer project, zero external contributors. The benefits of
canary (external testers, integration testing) are real but only kick in when
the project has external consumers of its pre-merge builds. Today,
@deessejs/fphas one maintainer and no non-maintainer PRs in flight. The operational cost outweighs the benefits.
When those conditions change — multiple maintainers, external contributors, or consumers wanting to validate pre-merge builds — canary snapshots become valuable enough to justify the operational cost.
This is the spec for a future canary implementation, captured so it is not lost. The current implementation is the two-channel pipeline documented in the Release Process (stable release + hotfix path).
Canary fires on every push to a PR, not on merge. This is the opposite of
publish.yml, which fires on pull_request: closed (merge only). The goal is to
publish a fresh snapshot every time the PR's branch is updated.
on:
pull_request:
types: [opened, synchronize, reopened]
branches: [staging]- Checkout the PR head.
-
pnpm install --frozen-lockfile. -
pnpm build. The artifact is needed for the smoke test and for publishing. - Smoke test on the built artifact (same shape as
publish.yml). -
pnpm changeset version --snapshot canary. This bumps the version inpackage.jsonwithout committing, and without producing a CHANGELOG entry. -
pnpm changeset publish --tag canary --no-git-tag. Publishes under thecanarydist-tag. No git tag is created (snapshots are not versions). - Comment on the PR with the install command:
pnpm add @deessejs/fp@canary. - Anti-republish guard: if the same snapshot is already published, skip.
-
Environment: a separate
canaryGitHub environment, with no required reviewers. The snapshot is automated, not gated. -
Permissions:
id-token: write(for the Trusted Publisher slot),contents: read,pull-requests: write(to comment on the PR). -
Trusted Publisher: a separate entry on npmjs.com, distinct from the
publish.ymlentry. The canary entry'sWorkflow filenameiscanary.yml.
- It does not push a git tag.
- It does not create a GitHub Release page.
- It does not write to
CHANGELOG.md. - It does not trigger
publish.yml(no merge required). - It does not post the changelog summary anywhere.
It is purely a build artifact on npm with a stable identifier per PR.
-
Public pollution: every push to every PR publishes a package on the public
npm registry under
@deessejs/fp@canary. This is deliberate (so external consumers can install), but the package appears in search results and on npmjs.com pages. -
Concurrent PRs: two PRs publishing snapshots at roughly the same time
collide on the
canarydist-tag. The earlier snapshot is no longer installable as@canarywithout specifying a version. With versioned snapshots like1.2.3-canary-<pr>-<sha>, each PR has a stable identifier, but consumers who install@canarywithout a version get the most recent push across all PRs. -
Trusted Publisher slot: each Trusted Publisher entry is registered with a
specific
Workflow filename. The currentpublish.ymlentry cannot be reused forcanary.yml. A second entry must be registered on npmjs.com. -
Build artifacts in npm cache: every snapshot adds a download artifact on
npm. For high-volume projects, this is a non-trivial cost. For
@deessejs/fptoday, with one PR per week at most, the cost is negligible.
pkg.pr.new (maintained by Vercel) is a better tool for canary distribution than
a custom workflow. It handles concurrent PRs natively (each PR gets its own URL
like https://pkg.pr.new/owner/repo@sha), and it does not pollute the npm registry.
If canary snapshots are ever implemented, the right path is likely:
- Install
pkg.pr.newas a GitHub Action in.github/workflows/canary.yml. - Configure it to publish on every push to a PR.
- Optionally configure a fallback comment with the
pkg.pr.newURL. - Skip the npm-publish path entirely.
This avoids the public pollution concern and the Trusted Publisher slot concern. The only cost is depending on Vercel's service availability.
Re-open the canary question when any of the following becomes true:
- The project has external contributors (PRs from non-maintainers).
- Two or more maintainers are actively reviewing PRs.
- A downstream consumer of
@deessejs/fp(another package, an internal app) requests pre-merge builds to test against. - The maintainer wants to release preview versions for stakeholder demos.
Until one of these triggers fires, the simpler two-channel pipeline (stable release
- hotfix path) is enough.
- Release Process — the current two-channel pipeline.
- Hotfix Flow — the urgent-fix path.
- Authoring Changesets — how to write a Changeset file.
- Internal:
docs/engineering/process/canary.md— the operational mirror of this page. - Internal:
docs/engineering/plans/release-pipeline.md§ 8.1 — the senior plan's canary design.
This wiki is maintained alongside the @deessejs/fp package. Pages here mirror internal documentation at docs/engineering/ in the repository; the repo file is the source of truth.
- Repository: source code, issues, releases.
- npm package: install, changelog, version history.
- Issue tracker: bug reports and feature requests.
- Discussions: questions and design conversations.