# Source Releases This procedure is for maintainers publishing Notarius source releases. A release is an immutable lightweight `vMAJOR.MINOR.PATCH` tag on `main` together with its checked-in `docs/releases/.md` note. Tag CI validates that source candidate after publication; it does not publish or repair a release. Notarius publishes no binaries, archives, checksums, signatures, containers, package-manager entries, or Gitea release objects. Windows is not supported. Do not create retrospective notes for the pre-procedure `v0.1.0`, `v0.2.0`, or `v0.3.0` tags. ## Select And Describe The Release Choose an unused stable semantic version in the form `vMAJOR.MINOR.PATCH`. Prereleases are not supported. Before `v1.0.0`, a minor release may change a documented CLI, configuration, durable artifact, integration, or operating contract when its note explains the impact and required operator action. A patch release must not intentionally break those documented contracts within its minor line. Create the version-matched note as part of the candidate. Every new note uses this structure, with concise, truthful content in each section: ```markdown # Notarius vMAJOR.MINOR.PATCH This release ... ## Summary ## Compatibility ## Upgrade ## Changes ``` The note is a historical summary. Link to current canonical documentation for exact behavior, and update that documentation in the candidate rather than using the note as a substitute. ## Prepare The Candidate Set the selected release version and disable Go workspace use for every candidate command: ```sh RELEASE_VERSION=vMAJOR.MINOR.PATCH export RELEASE_VERSION GOWORK=off ``` Run the shared source-candidate checks from the repository. They cover module hygiene, tests, race tests, vet, builds, formatting, whitespace, maintained configuration validation, and the Linux and Darwin command-build matrix: ```sh ./scripts/check-release-source.sh "$RELEASE_VERSION" ``` Before committing, manually follow every changed local Markdown link and review the candidate for unintended files, generated output, credentials, or other unrelated changes. Commit the release note and all affected current documentation, then run the shared checker against that exact candidate. Push the candidate commit to `main` only after it succeeds. Record the exact commit only after that push: ```sh RELEASE_COMMIT=$(git rev-parse 'HEAD^{commit}') export RELEASE_COMMIT ``` For private-module installation, configure standard `GOPRIVATE` matching this module and ordinary Git authentication for the hosting service before running the verification below. The exact authentication mechanism belongs to the maintainer environment; never record credentials or environment dumps in a release note, command history, or repository file. ## Guard And Publish The Tag Fetch current remote references, then run this guard without editing the candidate. It requires `main`, a clean worktree and index, disabled workspace use, a stable release version, the recorded and pushed commit, a matching note, and unused local and remote tags: ```sh git fetch origin main --tags if ! printf '%s\n' "$RELEASE_VERSION" | grep -E -x 'v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)' >/dev/null then printf '%s\n' "invalid release version: $RELEASE_VERSION" >&2 exit 1 fi test "$GOWORK" = off test "$(git branch --show-current)" = main test -z "$(git status --porcelain)" test "$RELEASE_COMMIT" = "$(git rev-parse 'HEAD^{commit}')" test "$RELEASE_COMMIT" = "$(git rev-parse 'origin/main^{commit}')" test -s "docs/releases/$RELEASE_VERSION.md" grep -F -x "# Notarius $RELEASE_VERSION" "docs/releases/$RELEASE_VERSION.md" for heading in '## Summary' '## Compatibility' '## Upgrade' '## Changes'; do grep -F -x "$heading" "docs/releases/$RELEASE_VERSION.md" done if git rev-parse -q --verify "refs/tags/$RELEASE_VERSION" >/dev/null; then printf '%s\n' "local tag already exists: $RELEASE_VERSION" >&2 exit 1 fi if git ls-remote --exit-code --tags origin "refs/tags/$RELEASE_VERSION" >/dev/null 2>&1; then printf '%s\n' "remote tag already exists: $RELEASE_VERSION" >&2 exit 1 fi ``` Create an explicitly lightweight tag against the guarded commit, verify its target, and push only that tag ref: ```sh git -c tag.gpgSign=false tag "$RELEASE_VERSION" "$RELEASE_COMMIT" test "$(git cat-file -t "$RELEASE_VERSION")" = commit test "$(git rev-parse "$RELEASE_VERSION^{commit}")" = "$RELEASE_COMMIT" git push origin "refs/tags/$RELEASE_VERSION:refs/tags/$RELEASE_VERSION" ``` Never use `git push --tags`, move a published tag, or delete a published tag. ## Verify The Published Release Confirm that the remote tag still points at the guarded commit and that the note is available from the tagged tree: ```sh REMOTE_TAG_COMMIT=$(git ls-remote origin "refs/tags/$RELEASE_VERSION" | awk '{print $1}') test "$REMOTE_TAG_COMMIT" = "$RELEASE_COMMIT" git show "$RELEASE_VERSION:docs/releases/$RELEASE_VERSION.md" >/dev/null ``` Verify a fresh source installation and its diagnostic version. The temporary directory confines the installed command to this check: ```sh release_verification_dir=$(mktemp -d) trap 'rm -rf "$release_verification_dir"' 0 HUP INT TERM mkdir -p "$release_verification_dir/bin" GOWORK=off GOBIN="$release_verification_dir/bin" go install \ "gitea.maximumdirect.net/eric/notarius/cmd/notarius@$RELEASE_VERSION" test "$("$release_verification_dir/bin/notarius" --version)" = "notarius $RELEASE_VERSION" ``` An exact fresh checkout and `GOWORK=off go build ./cmd/notarius` is an equivalent source verification when local installation policy requires it. `notarius --version` is diagnostic only; downstream compatibility remains defined by the published receipt and artifact contracts. ## Failure And Correction Policy If candidate validation fails before publication, fix the candidate on `main`, rerun the shared checker, and repeat the guards. An unpublished local tag may be deleted after inspection. If the remote tag or tag CI reveals a defect, leave the published tag intact. Fix the defect on `main`, choose a new patch version, write a new matching note, and repeat this procedure. Do not weaken tag immutability or add release assets as a workaround.