diff --git a/docs/development.md b/docs/development.md index 20e8ddf7..09905c2d 100644 --- a/docs/development.md +++ b/docs/development.md @@ -25,6 +25,7 @@ implemented component map. | LLM clients, prompts, schemas, profiles, or scheduling | [LLM Runtime](internal/llm.md) | It documents the transport boundary and PromptKit integration. | | Output, cache, resume, or debug artifacts | [Run State Internals](internal/state.md), [Operations](operations.md), and [Configuration](config.md) | These separate implementation details, operator behavior, and configuration contracts. | | External input formats, artifact schemas, or durable output files | [Integration Contracts](integrations/) | Integration documents define external and durable data contracts. | +| Release preparation, tagging, publication, or verification | [Source Releases](release.md) and [Documentation Policy](policy/documentation.md) | The release procedure owns maintainer guards and immutable-tag recovery; the policy assigns release-note ownership. | | Proposed or unimplemented behavior | [Roadmap](roadmap/) | Future work belongs only in roadmap documentation until implemented. | For an existing subsystem, also inspect its focused tests and the package-local diff --git a/docs/policy/documentation.md b/docs/policy/documentation.md index bb684cb8..74fff09a 100644 --- a/docs/policy/documentation.md +++ b/docs/policy/documentation.md @@ -65,6 +65,8 @@ secret values. | CLI contract | `docs/cli.md` | Commands, arguments, flags, invocation semantics, and exit codes. | End-to-end operating procedures, configuration field definitions, runtime filesystem layout, module implementation details. | | Configuration contract | `docs/config.md` | Discovery and precedence, file schema, fields, defaults, environment overrides, validation rules, and user-selectable module or validator keys. | Complete example files, CLI syntax, runtime state lifecycle, module implementation details. | | Operations | `docs/operations.md` | Runtime workflows, physical filesystem and state layout, output, cache, and debug handling, resume, cleanup, permissions, recovery, and operational limits. | CLI flag syntax, configuration field definitions, logical output schemas, implementation mechanics. | +| Source release procedure | `docs/release.md` | Maintainer release selection, candidate validation, tagging, publication guards, verification, and immutable-tag recovery. | Product installation summary, CLI version semantics, historical release summaries, CI implementation detail. | +| Release-note history | `docs/releases/` | One checked-in historical summary for each source release made under the procedure. The note at the immutable tag is that release's record. | Current commands, behavior, contracts, and compatibility definitions. | | Public HTTP contract, if introduced | `docs/api.md` | Routes, authentication, media types, request and response schemas, status codes, pagination, caching, idempotency, rate limits, and HTTP retry semantics. | Client walkthroughs, upstream or downstream integration internals, implementation detail. | | Consumer guidance, if a public package or API is introduced | `docs/consumers/` | Task-oriented use of the public interface, minimal client examples, and consumer responsibilities. | HTTP wire semantics, external protocol contracts, internal implementation detail. | | External and durable integration contracts | `docs/integrations/` | External file formats and protocols, upstream and downstream contracts, logical output bundle paths and schemas, media types, and compatibility behavior. | Physical runtime placement and lifecycle, internal transformations, CLI syntax, configuration defaults. | @@ -95,6 +97,14 @@ runtime state and how to operate or recover the application. When a workflow crosses these topics, choose the document that owns the task and link to the other contracts. +### Releases + +`docs/release.md` owns the source-release procedure. Release notes are +historical summaries, not current-state contract owners: the checked-in note at +an immutable tag records that release, while current canonical documentation +must change with the behavior it describes. Do not use a release note to defer +or replace current documentation updates. + ### Contracts And Implementation Integration and API documents define externally observable shapes and diff --git a/docs/release.md b/docs/release.md new file mode 100644 index 00000000..e34d3c38 --- /dev/null +++ b/docs/release.md @@ -0,0 +1,158 @@ +# 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, the recorded and pushed commit, a matching note, and unused local and +remote tags: + +```sh +git fetch origin main --tags + +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. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 53b98a89..e2712942 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -243,7 +243,7 @@ the pre-release confidence boundary. - The pipeline cannot publish binaries, releases, checksums, or other assets and requires no release secret. -## Stage 4: Establish The Canonical Release Procedure And Documentation Policy +## Stage 4: Establish The Canonical Release Procedure And Documentation Policy ✅ ### Goal