Release guide¶
Fontdone publishes one Cargo crate, fontdone, one npm package, fontdone,
and a native C SDK on GitHub Releases. The internal fontdone-c-abi and
fontdone-wasm Cargo packages have publish = false. There is no PyPI package.
Latest release: 2.14.3-alpha.11.
Publication uses this repository's tag-triggered release.yml and GitHub OIDC.
Alpha releases retain incomplete C-replacement and benchmark goals. Deprecated
FreeType aliases remain part of the pinned compatibility contract.
1. Trusted publisher configuration¶
Configure these identities on the existing packages:
| Registry | Repository | Workflow filename | GitHub environment |
|---|---|---|---|
| crates.io | appunni-m/fontdone |
release.yml |
crates-io |
| npm | appunni-m/fontdone |
release.yml |
npm |
The publish jobs alone receive id-token: write. Crates.io authentication uses
rust-lang/crates-io-auth-action; npm uses Node 22.14.0 and npm 11.5.1 with
provenance. An environment configured with required reviewers will pause its
job until that review occurs. No repository secret containing a registry token
is needed. Keep publisher settings and workflow environment names identical.
This follows the isolated verification, artifacts, OIDC, and GitHub Release stages used by coverage-mcp's release workflow.
2. Alpha acceptance policy¶
Starting with alpha.7, incomplete source coverage and incomplete C-contract adoption are reported, and do not require 100% completion for an alpha release. This is a release acceptance change, not a claim of complete FreeType parity.
Every executed test remains required: the fast gate and MSRV, all runnable exact parity comparisons, Rust/C/WASM/npm consumers, five native or emulated platform contracts, package checks, dependency audits, and benchmark checks. Coverage collection must succeed and retain its actual totals. No source files, inputs, expected results, or uncovered lines are removed from measurement to meet this policy. Undefined C inputs remain explicitly named pending cases.
make release-verify runs the local alpha checks and reports contract debt.
make release-verify-complete additionally requires all twelve C-contract
categories. The latter needs five fresh platform bundles and remains the
stricter gate for a complete replacement claim. It also enforces performance
thresholds once the benchmark policy has completed its baseline-review phase.
That policy currently has no thresholds; alpha CI retains ten-sample benchmark
reports without claiming that a regression budget passed.
The compatibility snapshot and adoption guide distinguish completed functionality, measured runtime parity, historical coverage, and unfinished C-contract requirements.
The alpha.8 local verification on 2026-09-15 passes 20,357/20,357 runnable cases in each of the Rust, C ABI, and WASM coverage lanes, with three named undefined-C cases pending. The combined source report measures 66,270/68,525 lines (96.7092%), 12,189/13,836 branches (88.0963%), 3,849/4,137 functions (93.0384%), and 91,297/94,949 regions (96.1537%). The WinFNT record conversion is exercised by the retained header inputs. Big-endian-only branches require the separate PowerPC runtime lane and are not measured by this macOS report. GitHub produces its own report for the final tag; this local result does not stand in for a successful publishing job.
3. Prepare and verify a version¶
- Increment the root Cargo version, both private workspace versions and their
exact root dependency requirements, and the npm version together. Run
make release-lock-updateto synchronize only workspace lockfile entries using the already downloaded dependency set. - Update the changelog, documentation source-version field, and package contracts.
Keep public installation blocks on the last published version. Regenerate derived
ABI metadata with
make generate-contracts. - Run
make test-parityandmake record-parity-snapshot. This binds the reported comparison counts to the measured sources. Then refresh the file ledger withmake repository-inventory. - Run
make ci-fastusing the pinned font-generation Python environment described in Development. Inspect packages withmake release-dry-run. Usemake release-verifyfor a local thorough run. - Commit, push to
main, and require successful CI for that exact commit. - Create an annotated, unused
v<version>tag on that commit and push it. Never move a published tag or overwrite an existing registry version.
For the published release, registry consumers use:
[dependencies]
fontdone = "=2.14.3-alpha.11"
A development path or pinned Git revision may be added, but a publishable consumer must retain the exact registry version.
4. What the tag runs¶
The tag starts the full CI matrix. Release preflight waits for successful CI on the exact tag commit; a fast branch run cannot satisfy that gate. It verifies the annotated remote tag object, synchronized versions, and downloads that run's checked Cargo/npm packages and platform evidence. It builds the native C SDK and produces a checksum manifest excluding the manifest itself.
The crates.io job compiles the packaged source before authentication and
compares the resulting archive with the downloaded CI artifact. Only then does
it mint an OIDC token and run make release-publish-oidc VERIFIED_CRATE=....
The helper rejects local invocation, the wrong repository/tag, missing OIDC
context, dirty sources, and archive differences. Cargo's duplicate verification
is skipped only after the identical archive has been compiled before token
minting. The published registry checksum must match the verified archive.
The npm job checks the bundle checksum and publishes the exact tested .tgz
with provenance under next. Existing versions are accepted only when the
registry integrity matches the candidate; network errors are not treated as
missing versions.
make npm-package-verify also stages a one-directory relative archive and runs
the same publish helper in offline dry-run mode. An existing artifact can be
checked with make release-npm-verify VERIFIED_NPM_ARCHIVE=<path>; real uploads
use make release-npm-publish-oidc in the exact GitHub tag job. Both paths resolve
the local filename before npm sees it, because
npm package specifiers
otherwise interpret release-bundle/archive.tgz as GitHub shorthand. Failed
uploads expose a bounded diagnostic in the public workflow annotations.
Only after both registries succeed does the final job attest the artifacts and
create the GitHub prerelease with compatibility notes, Cargo archive, npm
archive, native SDK, and SHA256SUMS. GitHub Release commands specify the
repository explicitly, including jobs without a source checkout.
5. Recovery and verification¶
Inspect the first failed job and its retained diagnostics. A skipped publish job has not tested OIDC authentication. A publisher identity rejection in a running publish job is a registry configuration issue; a failed parity, coverage-collection, or package job is a repository issue.
Rerun a transient failure on the same immutable tag. If source or workflow changes are needed, make a new version and tag. A partially published version must not be rebuilt into different bytes. Preserve earlier failed tags and run records as history.
After publication, check the exact crates.io version and checksum, npm version and provenance, and the GitHub prerelease assets. Confirm a fresh registry consumer can install and exercise the released APIs. A green preflight alone is not evidence that either registry accepted the release.
Refresh user documentation after publication¶
Wait for every registry job and the GitHub release to succeed, then run:
make docs-release-refresh
make docs-release-check docs-registry-examples
Review and commit the refreshed release record and installation blocks. The Documentation workflow checks freshness after a successful tag release and on its daily schedule. Keep source-candidate versions separate from published installation versions; do not send users to a version that is still building.