Maintainer release workflow
This page is for Harn maintainers cutting a release. User-facing CLI behavior lives in CLI reference.
Standard flow#
Live releases run from the protected hosted workflow owned by
burin-labs/harn-bump-fleet. Start from an up-to-date Harn checkout, freeze the
exact remote source SHA, and dispatch the Fleet workflow:
git fetch origin main
HARN_RELEASE_SHA="$(git rev-parse origin/main)"
gh workflow run hosted-release.yml \
--repo burin-labs/harn-bump-fleet \
-f bump=patch \
-f mode=ship-pr \
-f at_sha="${HARN_RELEASE_SHA}"
Approve the run's protected release environment, then follow the exact run
until it hands off the immutable tag and release PR. Once the tag is known,
resume Fleet's durable post-tag watcher from a harn-bump-fleet checkout:
scripts/watch_harn_release.sh \
--tag vX.Y.Z \
--repo ../harn \
--yes-live-release
The hosted workflow owns source freezing, audits, hosted platform certification, the GitHub-signed release commit, immutable tag, release PR, and auto-merge. The watcher is resumable by exact receipt and owns missing-asset recovery, PR re-arming, release finalization, main-cache warming, and transient ref cleanup. A visible tag or prerelease is an intermediate state, not release completion.
Do not invoke scripts/release_ship.sh or the local release_harn.harn harness
for a normal live release. They are implementation and development surfaces;
the hosted workflow is the authority boundary for release credentials,
signatures, and protected-environment approval. If a run stops after the tag is
published, rerun the watcher first: it reuses the immutable attempt and avoids
duplicating accepted builds or publication work.
Before cutting a release that adds a new hard preflight requirement, verify its user-facing documentation includes an equivalent migration note: the exact command for auditing data accepted by the prior release, a typed non-success status that cannot be mistaken for compliance, the records requiring review, and the exact command that returns the user to strict mode. A compatibility path may support review, but it must not manufacture evidence or weaken the final production/export gate.
Rehearse release changes offline#
Before tagging, run the fixture rehearsal with an installed Harn binary:
HARN_BIN="$(command -v harn)" bash scripts/release_rehearsal.sh
The rehearsal executes the same staging script used by publication jobs, then checks archive provenance, publication policy, and development cutover in local fixtures. It creates no remote tags or releases. Missing staged dependencies, copied or duplicated staging steps, and an unreported cutover must fail.
CI runs this rehearsal for release-related pull requests and every main push.
Its verdict is required by CI status. This fixture proof does not replace the
hosted platform certification or prove that live publication credentials work.
Hosted platform certification#
Release preparation is fail-closed on the frozen remote source SHA. Before the
version/changelog commit is created, the release harness dispatches
.github/workflows/windows-nightly.yml and
.github/workflows/macos-nightly.yml for the frozen source branch while the
local source audit runs. GitHub must return an exact run ID for each dispatch.
Both runs and their full-workspace jobs must complete successfully with the
expected workflow path, event, SHA, URL, and unique job identity.
Windows certification stays off the contended Actions cache namespace.
Successful main windows-nightly runs publish a short-retention
workspace-windows-warm workflow artifact; release-certify/<sha> consumers
restore that artifact read-only into a larger Dynamic Dev Drive ceiling and
fall cold when no compatible generation exists. Cargo still owns exact-source
invalidation after the restore. Artifact name, retention, size budget, and Dev Drive ceilings are owned by
.github/cache-policy.json (windows_workspace_warm); the workspace
cargo-nextest pin is the top-level nextest_version in the same document.
scripts/check_ci_cache_policy.harn locks both surfaces, and CI scripts load
them through scripts/ci/cache_policy.sh.
The resulting harn.release_audit_receipt.v2 records the certified source SHA,
run/job URLs and IDs, per-lane timings, and critical path. The harness re-reads
the remote branch after the join; movement invalidates the whole receipt. The
release harness runs the residual checks affected by release metadata, creates
the synthetic release commit, and then proves that commit has exactly the
certified SHA as its sole parent.
If a hosted run fails or is cancelled, fix the source or runner problem and restart the release from the still-unmodified source branch. If a valid exact run is already recorded, reuse its receipt; do not dispatch a blind duplicate. If the branch moved, discard both platform receipts and freeze the new SHA.
Diagnose a source audit failure#
Open the failed hosted release artifact and read release-audit.json. Find the
hosted-platform-certification step. Its output ends with RELEASE AUDIT FAILURE RECAP, the failed lane, its exit status, and the last 40 log lines.
Use that cause to choose the narrowest local check. Do not rerun a release only
because the workflow page shows a generic harn-audit failed message.
For a Harn conformance failure, rerun the named file with the frozen candidate binary and the release network environment cleared:
env -u HARN_EGRESS_ALLOW \
-u HARN_EGRESS_DENY \
-u HARN_EGRESS_DEFAULT \
-u HARN_EGRESS_BLOCK_PRIVATE \
-u HARN_EGRESS_ALLOW_LOOPBACK \
HARN_BIN=/path/to/frozen/harn \
./scripts/harn_bin.sh -- test conformance --filter <case name>
If the focused test passes, replay the full conformance set more than once. Treat one pass as evidence of a transient failure, not proof that the cause is gone. Keep the failed receipt and the replay logs with the release record.
Piecewise gates#
Use the repository-local gates only when you need to audit or dry-run without opening a release PR:
./scripts/release_gate.sh audit
./scripts/release_gate.sh full --bump patch --dry-run
scripts/publish.sh is the thin entrypoint for the Harn publisher used by the
release gate. Live publication probes each crate version, resumes the remaining
dependency DAG, and waits with bounded backoff before publishing dependents of
newly uploaded crates. It emits a JSON receipt separating published,
already-present, waiting, failed, and remaining crates. Dry-run mode continues
to use Cargo's workspace dry-run because it has no remote recovery state.
Release artifacts#
Every published release uploads five per-target archives, a
coreutils-format SHA256SUMS manifest, and a structured
release-assets.json manifest. Downstream packagers
(downstream fetch-harn.sh scripts, npm CLI postinstall hooks,
Scoop/Homebrew formula generators) should prefer the structured
manifest. See Release assets manifest
for the schema and stable URLs.