diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md index 39699604..8bf79020 100644 --- a/docs/roadmap/future.md +++ b/docs/roadmap/future.md @@ -153,7 +153,6 @@ section only after a concrete workflow, contract, and priority emerge. ### Distribution And Operations - Packaged release artifacts for alpha distribution. -- A documented versioning and release process. - Optional generated example-output fixtures with a regeneration procedure. - Additional diagnostics or reporting views. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md new file mode 100644 index 00000000..354ef58c --- /dev/null +++ b/docs/roadmap/implementation.md @@ -0,0 +1,428 @@ +# Source-Only Release Implementation Plan + +## Purpose + +Implement the target state defined by +[Source-Only Releases](source-releases.md): immutable source tags with checked-in +release notes, a diagnostic version interface, strong shared candidate checks, +validation-only tag CI, Linux support, best-effort macOS compilation, and no +packaged binaries or Windows support. + +This plan is ordered. Each numbered stage is one implementation prompt for a +gpt-5.6-terra coding agent. Complete and validate one stage before beginning +the next. Preserve all unrelated worktree changes, follow every policy under +`docs/policy/`, and update current-behavior documentation in the same stage as +the behavior it describes. + +Do not create or push a release tag while implementing this plan. Do not invent +a release note for `v0.1.0`, `v0.2.0`, or `v0.3.0`. The first real release +under the completed procedure will add its own note in a separate release +operation. + +## Decisions Fixed For Implementation + +- Releases are stable `vMAJOR.MINOR.PATCH` source tags on `main`; prereleases + are unsupported initially. +- Tags are lightweight and immutable after publication. +- No release binaries, archives, checksums, signatures, containers, + package-manager entries, or Gitea release objects are produced. +- Linux is supported. Release checks compile Linux `amd64` and `arm64` with + `CGO_ENABLED=0`. +- macOS is best-effort. Release checks compile Darwin `amd64` and `arm64` with + `CGO_ENABLED=0`, without promising runtime CI or packaged output. +- Windows is unsupported and must not be added to build checks. +- Release notes begin with the first release made under the new procedure; + historical tags are left untouched. +- `notarius --version` is informational. Receipt and artifact contracts remain + authoritative for downstream compatibility. +- One checked-in POSIX shell command owns substantive source-candidate checks. + The release procedure and tag CI call it rather than maintaining duplicate + test/build matrices. +- Tag CI validates only. Pre-publication local guards remain mandatory because + tag CI cannot prevent an already-pushed tag. + +## Stage 1: Add Build Version Resolution And `--version` + +### Goal + +Add a small, testable build-information boundary and expose the public root +version flag without affecting existing command behavior. + +### Implementation + +1. Create `internal/buildinfo` with an exported link-time string variable named + `Override` and an exported resolver such as `Version() (string, error)`. + Keep this package independent of CLI and application packages. +2. Resolve the displayed value using this precedence: + 1. a nonempty `Override`; + 2. the main-module version returned by `runtime/debug.ReadBuildInfo`; then + 3. the literal `development`. +3. Accept a release value only when it matches the complete stable SemVer tag + form `^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$`. + Whitespace, prerelease/build suffixes, pseudo-versions, and arbitrary text + are not release versions. A nonempty invalid linker override is an error; + an empty, `(devel)`, pseudo-version, or otherwise non-release main-module + version falls back to `development`. +4. Add `--version` to the root dispatch in `internal/cli`. It is valid only as + the sole argument, writes exactly `notarius \n` to stdout, + writes nothing to stderr, and exits zero. Additional arguments are a syntax + error using the existing exit-2 and stderr conventions. An invalid linker + override is a runtime/build error using exit 1 and stderr. +5. Add the flag to root usage without changing the existing behavior of empty + arguments, help spellings, or subcommands. +6. Update `docs/cli.md` as the canonical public contract and + `docs/internal/cli.md` as the implementation owner. State that tagged + `go install` builds can obtain the main-module tag from Go build information, + controlled builds may inject + `gitea.maximumdirect.net/eric/notarius/internal/buildinfo.Override`, and an + ordinary unversioned checkout reports `development`. + +### Tests + +- Add table-driven `internal/buildinfo` tests for valid stable versions, + leading-zero rejection, whitespace, prerelease/build suffixes, pseudo- + versions, override precedence, invalid nonempty override, and development + fallback. Test the pure resolution decision rather than trying to mutate + process build information. +- Extend the CLI command-contract tests to cover exact stdout/stderr/exit + behavior for `--version`, extra arguments, and unchanged help/unknown-command + behavior. +- Do not snapshot the whole usage document solely for the new line; assert the + stable semantic fragments already owned by the CLI contract tests. + +### Validation + +```sh +go test ./internal/buildinfo ./internal/cli +go test ./... +go vet ./... +go build ./cmd/notarius +go run ./cmd/notarius --version +``` + +Build a temporary Linux host binary with: + +```sh +go build -trimpath \ + -ldflags '-X gitea.maximumdirect.net/eric/notarius/internal/buildinfo.Override=v0.0.0' \ + -o /path/to/temp/notarius ./cmd/notarius +``` + +and verify that its output is exactly `notarius v0.0.0`. + +### Acceptance Criteria + +- The public and internal documentation matches the implemented version + behavior. +- Ordinary builds print `notarius development`. +- A valid linker override prints the exact stable tag. +- Invalid linker content cannot masquerade as a release version. +- Existing CLI commands, help, streams, and exit classes remain unchanged. + +## Stage 2: Add One Reusable Source-Candidate Checker + +### Goal + +Create one repository-owned, offline validation command used identically by a +maintainer and release CI. + +### Implementation + +1. Create executable POSIX shell script `scripts/check-release-source.sh`. + Require exactly one positional argument containing a stable SemVer tag. The + script must locate and enter the repository root from its own checked-in + path so callers cannot accidentally validate another working directory. +2. Use `set -eu`, quote all expansions, reject invalid versions before using + them in paths or linker arguments, and use a freshly created temporary + directory for cross-build output. Install a cleanup trap scoped only to that + resolved temporary directory. +3. Keep release-note, branch, remote, clean-worktree, and tag-existence guards + out of this script. Those publication-specific checks belong in + `docs/release.md` and tag CI. This script owns the substantive source checks + that both workflows share. +4. Implement these checks in a clear fail-fast order: + - require the expected Notarius module path in `go.mod`; + - reject tracked `go.work` or `go.work.sum`, an existing `vendor` directory, + and any `replace` directive in `go.mod`; + - `GOWORK=off go test -count=1 ./...`; + - `GOWORK=off go test -race -count=1 ./...`; + - `GOWORK=off go vet ./...`; + - `GOWORK=off go build ./...`; + - `GOWORK=off go mod tidy -diff`; + - require no output from `gofmt -l` for tracked Go files; + - `git diff --check` and `git diff --cached --check`; + - validate `examples/dnd-minimal.config.yml` and + `examples/dnd-complete.config.yml` for pipeline `dnd-session` using the + built or `go run` Notarius command; + - build `./cmd/notarius` with `CGO_ENABLED=0` for Linux `amd64` and `arm64` + and Darwin `amd64` and `arm64`; and + - inject the supplied tag through `internal/buildinfo.Override` in every + cross-build. +5. Execute the built command and verify exact `--version` output when the + current host GOOS/GOARCH matches one of the four targets. Do not attempt to + execute a foreign target. +6. Do not compile for Windows, write output beneath the repository, contact an + LLM provider, require credentials, or mutate tracked files. + +### Tests And Validation + +- Run the script with `v0.0.0` as a synthetic build version. It does not require + or create a corresponding release note or Git tag. +- Exercise its cheap argument guards separately with missing, extra, malformed, + prerelease, and leading-zero versions. These failures must occur before Go + tests or builds begin. +- Confirm temporary outputs are removed on success and ordinary command + failure. Do not add a large shell-test framework solely for this script; + retain focused automated tests only if they protect a realistic failure that + is not more clearly covered by executing the checker itself. + +```sh +./scripts/check-release-source.sh v0.0.0 +git status --short +``` + +### Acceptance Criteria + +- One command runs every substantive source-candidate check required by the + feature roadmap. +- The command is deterministic, offline, credential-free, POSIX-compatible, + fail-fast, and safe with temporary paths. +- The Linux and Darwin target matrix succeeds and Windows is absent. +- Version injection and host-binary reporting are checked as part of the same + matrix. +- Successful execution leaves the worktree and index unchanged. + +## Stage 3: Add Validation-Only Tag CI + +### Goal + +Independently validate every newly pushed release tag without publishing or +mutating release state. + +### Implementation + +1. Add `.woodpecker/release.yml` triggered only by tag events. +2. Use the Go 1.25.5 container image to match the version currently declared + by `go.mod`. When the declared Go version changes in a future release, the + release pipeline image and release documentation must be reviewed in the + same change. +3. In one validation step: + - read the candidate version only from `CI_COMMIT_TAG`; + - require the stable SemVer form fixed above; + - require a nonempty `docs/releases/$CI_COMMIT_TAG.md`; + - require the exact heading `# Notarius $CI_COMMIT_TAG`; + - require exact `## Summary`, `## Compatibility`, `## Upgrade`, and + `## Changes` headings; and + - invoke `./scripts/check-release-source.sh "$CI_COMMIT_TAG"`. +4. Do not include a release plugin, API token, artifact upload, Gitea release + creation, archive/checksum step, Windows target, tag mutation, or retry that + could overwrite published state. +5. Keep the CI file thin: note/tag guards belong in it, while the substantive + source checks remain in the shared script. + +### Validation + +- Review the YAML trigger and commands against the repository's Woodpecker + syntax and the established Weatherreporter tag pipeline structure. +- Confirm every invoked path exists and the script is executable. +- Run the shared checker locally with `v0.0.0`. +- Search the new pipeline for release-plugin configuration, upload commands, + secrets, Windows targets, and mutation commands; none may be present. +- Run `git diff --check`. + +Do not push a synthetic tag merely to test this stage. The first real release +will exercise the remote trigger; local source validation and review provide +the pre-release confidence boundary. + +### Acceptance Criteria + +- Every stable release tag triggers the validation pipeline. +- Missing or malformed version-matched release notes fail before the expensive + source checks. +- CI calls the same substantive checker used locally. +- 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 + +### Goal + +Make the complete source-release workflow executable by a maintainer without +undocumented knowledge, and give release documentation an explicit canonical +home. + +### Implementation + +1. Create `docs/release.md`, adapted to Notarius's source-only model. It must + define: + - stable SemVer selection and the pre-`v1` compatibility policy; + - the exact `docs/releases/.md` template and validation guards; + - invocation of `./scripts/check-release-source.sh "$RELEASE_VERSION"`; + - manual review of changed Markdown links and unintended repository files; + - committing and pushing the release note and current documentation before + tagging; + - recording `RELEASE_COMMIT` from `HEAD^{commit}`; + - a copyable guard that requires `main`, a clean worktree/index, disabled Go + workspace use, an exact match between `RELEASE_COMMIT` and + `origin/main`, a matching note, and an unused local and remote tag; + - explicit lightweight-tag creation against `RELEASE_COMMIT`; + - pushing only + `refs/tags/$RELEASE_VERSION:refs/tags/$RELEASE_VERSION`; + - remote tag and tagged-note verification; + - a fresh `go install ...@"$RELEASE_VERSION"` or fresh exact-tag checkout + verification, including exact `--version` output; and + - immutable-tag failure and correction policy. +2. The procedure must say that the tag and checked-in note are the release and + that tag CI is validation-only. It must explicitly exclude binaries, + archives, checksums, signatures, containers, package-manager publication, + Gitea release objects, Windows, and retrospective notes for existing tags. +3. Document private-module installation through standard `GOPRIVATE` and Git + authentication mechanisms without including credentials or private + environment dumps. Do not make one maintainer's credential setup part of + the release contract. +4. Update `docs/policy/documentation.md`: + - add canonical-owner rows for `docs/release.md` and `docs/releases/`; + - state that release notes are historical summaries, not current-state + contract owners; + - state that the checked-in note at the immutable tag is the release record; + and + - require current canonical docs to change with behavior rather than using + release notes as substitutes. +5. Update `docs/development.md` with a release-preparation/tagging/verification + routing row pointing to `docs/release.md` and the relevant policies. +6. Do not create an empty placeholder release note or a retrospective note. + `docs/releases/` first becomes tracked when the next actual release note is + prepared. + +### Validation + +- Follow every local Markdown link added or changed in this stage. +- Execute every non-destructive candidate-validation command that does not + require an actual new release note, remote tag, or publication. +- Compare the procedure line by line with the shared checker and CI so their + tag syntax, note headings, target matrix, and validation ownership agree. +- Confirm the procedure never uses `git push --tags`, moves a published tag, + uploads an asset, or embeds credentials. +- Run `git diff --check`. + +### Acceptance Criteria + +- `docs/release.md` is sufficient to prepare, guard, tag, publish, verify, and + recover from a source release. +- Release procedure and release-note ownership are explicit and nonduplicative. +- The procedure calls the shared checker rather than restating its full command + matrix. +- No historical or placeholder release note is introduced. + +## Stage 5: Align Platform, Installation, And Operational Documentation + +### Goal + +Make the supported-platform and source-installation story discoverable in the +canonical current-state documents without duplicating the release procedure. + +### Implementation + +1. Update `README.md` with a concise source-installation section. Show + `go install gitea.maximumdirect.net/eric/notarius/cmd/notarius@` as a + version-pinned pattern and retain the existing minimal product quickstart. + Link release maintainers to `docs/release.md` rather than reproducing its + guards. +2. Update `docs/operations.md` with operator-facing source deployment facts: + Linux support, the Go version declared by `go.mod`, version pinning, exact + tag builds, and `notarius --version` as a diagnostic. Link command semantics + to `docs/cli.md` and maintainer publication mechanics to `docs/release.md`. +3. Update `docs/policy/architecture.md` with the durable platform and + distribution invariants: supported Linux deployment, best-effort macOS + development, unsupported Windows, and source-only distribution. Keep tag + commands and release mechanics out of architecture. +4. Review `docs/internal/overview.md` navigation after adding + `internal/buildinfo`. Add only the smallest component entry needed if the + current inventory would otherwise omit a meaningful implemented boundary; + do not inflate build information into a subsystem. +5. Confirm `docs/roadmap/future.md` no longer lists the active documented + release-process work. Retain packaged alpha artifacts as deferred work; the + source-only release feature does not permanently reject reconsideration. +6. Review the completed feature roadmap against the implementation and correct + only genuine target-state inconsistencies. Do not convert it into a + changelog or duplicate `docs/release.md`. + +### Validation + +- Verify all added and changed local Markdown links. +- Confirm commands agree with the implemented CLI and declared module path. +- Confirm no current-state document claims that Notarius publishes binary + assets or supports Windows. +- Run: + +```sh +go run ./cmd/notarius --version +go run ./cmd/notarius help +git diff --check +``` + +### Acceptance Criteria + +- Users can discover how to install a pinned source release. +- Operators can identify the deployed version and understand the support + boundary. +- Architecture records durable platform/distribution policy without owning + maintainer release commands. +- Packaged artifacts remain clearly deferred rather than accidentally promised + or permanently prohibited. + +## Stage 6: Final Release-System Verification + +### Goal + +Review the implemented feature as one system and prove that code, +documentation, shared validation, and CI converge on the same release model. + +### Verification Work + +1. Inspect all commits associated with Stages 1–5 and compare the result with + `docs/roadmap/source-releases.md` and this plan. +2. Run the shared candidate checker with synthetic version `v0.0.0`. This is a + build identity only; do not create a note or tag for it. +3. Independently run the repository-wide baseline checks if any are not already + performed by the shared checker: + +```sh +go test ./... +go vet ./... +go build ./cmd/notarius +``` + +4. Verify exact development and injected release output: + - ordinary checkout: `notarius development`; + - injected `v0.0.0`: `notarius v0.0.0`; + - invalid linker override: nonzero exit, no false release identity. +5. Confirm both maintained D&D configurations validate offline. +6. Verify all added or changed local Markdown links and run + `git diff --check`. +7. Audit `.woodpecker/release.yml` and `docs/release.md` for agreement on tag + form, note location/headings, Go image/version expectations, and shared + checker use. +8. Confirm the repository contains no generated release binary, distribution + directory, checksum file, release credential, Windows target, release + plugin, synthetic release note, or new tag. +9. Review tests under the repository testing policy. Retain behavior-level + coverage for the public version contract and important validation guards; + remove redundant tests that merely duplicate the shared checker or CI text. +10. Report any remaining divergence as a concrete finding. Fix only in-scope + release-feature defects discovered during this verification; do not expand + into packaged distribution or unrelated cleanup. + +### Acceptance Criteria + +- All feature-roadmap acceptance criteria are met except creation of the first + real post-procedure release, which is intentionally a separate operator + action. +- Local validation and tag CI share one substantive source checker. +- Version reporting, source installation, platform policy, documentation + ownership, tag guards, and immutable failure handling are internally + consistent. +- The full test suite, vet, build, configuration validation, four-target cross- + build matrix, Markdown link review, and whitespace checks pass. +- The worktree contains no release side effects beyond the intended source, + automation, and documentation changes. diff --git a/docs/roadmap/source-releases.md b/docs/roadmap/source-releases.md new file mode 100644 index 00000000..b094e803 --- /dev/null +++ b/docs/roadmap/source-releases.md @@ -0,0 +1,281 @@ +# Source-Only Releases + +## Status + +Proposed. + +## Purpose + +Define a repeatable, guarded release process for Notarius without taking on a +binary-distribution system that its current operator audience does not need. +The process should make an exact source revision, its compatibility impact, +and its validation status easy to identify while keeping installation in the +hands of technically capable operators and deployment automation. + +The model is adapted from Weatherreporter's release procedure, but its target +is deliberately narrower: an immutable source tag and checked-in release note +are the release. Notarius does not publish executable archives or support +Windows as part of this work. + +## Release Model + +Notarius releases come from commits on `main` and use stable semantic-version +tags in the form `vMAJOR.MINOR.PATCH`. Prerelease tags are not part of the +initial process. + +Every release has one nonempty, version-matched note at +`docs/releases/.md`. The note and every affected current-state document +must be present in the tagged commit. The Git tag and checked-in note together +are the durable release record; no separately editable release page is +required. + +Published tags are immutable. A maintainer must never move, reuse, or delete a +published tag. If a published candidate is defective, the correction is made +on `main` and released under a new patch version. An unpublished local tag may +be deleted when candidate inspection finds a problem before any remote push. + +Before `v1.0.0`, a minor release may intentionally change a documented CLI, +configuration, durable artifact, integration, or operating contract when its +release note explains the impact and required operator action. A patch release +must not intentionally break those documented contracts within its minor +line. + +The existing `v0.1.0`, `v0.2.0`, and `v0.3.0` tags remain unchanged. They +predate this procedure and do not need retrospective release notes. The first +release made under this process establishes the release-note series. + +## Source-Only Distribution + +Notarius does not publish release binaries, archives, installers, container +images, package-manager entries, checksum files, or signatures. A release tag +is suitable for Go-native installation and for an operator-controlled build +from an exact checkout. + +The primary installation form is: + +```sh +GOWORK=off go install \ + gitea.maximumdirect.net/eric/notarius/cmd/notarius@vMAJOR.MINOR.PATCH +``` + +Operator documentation should also describe cloning the repository, checking +out the tag in detached-head state, and building `./cmd/notarius` with the Go +version declared by `go.mod`. Private-module authentication and `GOPRIVATE` +configuration belong to the operator environment and must be documented by +mechanism rather than with real credentials. + +Consumers such as Narratio should pin the desired Notarius tag in provisioning +or deployment configuration. They must continue to decide runtime +compatibility from Notarius's published receipt and artifact schema contracts, +not merely from the executable's product version. + +Packaged binaries may be reconsidered if distribution demand, installation +friction, or a broader user audience justifies their build, signing, retention, +and platform-support costs. They are not a prerequisite for a disciplined +release process. + +## Platform Policy + +Linux is the supported deployment platform. Release validation must run the +test suite and the release build on Linux and must confirm that the command +builds with `CGO_ENABLED=0` for Linux `amd64` and `arm64`. + +macOS is a best-effort development and testing platform. Release validation +should confirm that the command cross-compiles with `CGO_ENABLED=0` for Darwin +`amd64` and `arm64`, but the project does not promise packaged artifacts or a +separate runtime test environment for those targets. + +Windows is unsupported. The release process must not require Windows builds, +Windows-specific compatibility work, or Windows documentation. Platform- +specific implementation may intentionally use Unix facilities when they are +important to Notarius's filesystem safety and operational model. Any later +decision to support Windows requires its own feature scope and validation +policy. + +## Version Reporting + +Add a root `notarius --version` interface for deployment diagnostics. It +prints exactly one line: + +```text +notarius vMAJOR.MINOR.PATCH +``` + +when the build has a valid release version, and: + +```text +notarius development +``` + +when no release version is available. + +The implementation must obtain the main-module version from Go build +information so `go install ...@vMAJOR.MINOR.PATCH` reports the selected tag. It +must also accept an optional link-time version override so controlled builds +and release CI can identify an exact tag from a checkout. The override must be +validated and must not silently turn arbitrary text into a release version. +Ordinary unversioned checkout builds remain `development`; the release process +must not modify a tracked source constant for each release. + +Version reporting is an informational product interface. It does not replace +receipt, configuration, prompt, or artifact schema versioning, and it must not +be used as the sole downstream compatibility check. + +## Release Notes + +Each new `docs/releases/.md` document has this minimum structure: + +```markdown +# Notarius vMAJOR.MINOR.PATCH + +This release ... + +## Summary + +## Compatibility + +## Upgrade + +## Changes +``` + +The note should concisely explain the release's purpose, compatibility with the +preceding release, operator actions, and material user-visible, operational, +integration, and maintainer-visible changes. It should link to canonical +current-state documentation for exact contracts rather than duplicating those +contracts. + +Release notes are durable historical summaries. They must not contain +credentials, private infrastructure detail, sensitive campaign material, or +claims that are not true of the tagged candidate. A release note does not +excuse stale current-state documentation; affected canonical documents are +updated in the same candidate. + +## Candidate Validation + +The release procedure must provide copyable POSIX-shell guards that validate +the release version, release-note filename and heading, required note sections, +repository state, and module hygiene. Validation must be run from the Notarius +repository root with Go workspace behavior disabled. + +At minimum, a candidate must pass: + +- no tracked `go.work` or `go.work.sum`, no vendored tree, and no `replace` + directive in `go.mod`; +- `GOWORK=off go test -count=1 ./...`; +- `GOWORK=off go test -race -count=1 ./...`; +- `GOWORK=off go vet ./...`; +- `GOWORK=off go build ./...`; +- `GOWORK=off go mod tidy -diff`; +- `gofmt` verification for every tracked Go file; +- `git diff --check` and `git diff --cached --check`; +- validation of both maintained D&D configuration examples with their selected + pipeline; +- Linux `amd64` and `arm64` static command builds; +- best-effort Darwin `amd64` and `arm64` static command builds; and +- a focused manual or automated check that every added or changed local + Markdown link resolves. + +The candidate review also checks for generated binaries, test output, +credentials, temporary files, module replacements, vendored dependencies, and +other unintended source-control content. Tests remain offline and do not call +an LLM provider or require live credentials. + +## Candidate Publication + +The release procedure must guard the exact commit immediately before tagging. +It requires: + +- the current branch is `main`; +- the worktree and index are clean; +- the candidate commit has been pushed and exactly matches `origin/main`; +- the matching release note exists in that commit; +- no local or remote tag already uses the selected version; and +- the substantive release checks have passed for that exact candidate. + +The maintainer records the exact candidate commit, creates a lightweight tag +bound explicitly to that commit, verifies the local tag target, and pushes only +that tag ref. The procedure must not recommend `git push --tags`. + +After publication, the maintainer verifies that the remote tag resolves to the +guarded commit and that the release note can be read from the tagged tree. A +fresh temporary checkout or `go install ...@` must build successfully, and +the resulting command must report the expected version through `--version`. + +## Validation-Only Release Automation + +Add a tag-triggered Woodpecker pipeline that validates source releases without +publishing artifacts. It should: + +- accept only stable semantic-version tags; +- require the version-matched release note; +- run the same substantive module, test, race, vet, build, formatting, and + whitespace checks as the documented local procedure; +- validate the maintained configuration examples; +- perform the supported and best-effort cross-build checks; and +- verify a release-version build's `notarius --version` output on the CI host. + +The pipeline must not upload binaries, create archives or checksums, create or +edit a Gitea release object, or require a release API token. Local guards remain +authoritative before tag publication because CI begins only after the tag is +already remote. + +If tag validation fails, preserve the published tag, fix the cause on `main`, +select a new patch version, and repeat the full process. Do not weaken tag +immutability merely because the release contains source rather than binaries. + +## Documentation Ownership + +In the target state: + +- `docs/release.md` owns the maintainer release procedure, commands, ordering, + publication checks, and failure recovery; +- `docs/releases/` owns one historical summary per release made under the new + process; +- `docs/cli.md` owns the `--version` contract; +- `README.md` owns the shortest source-installation example and links to the + release procedure where useful; +- `docs/development.md` routes release preparation, tagging, and verification + work to `docs/release.md`; +- `docs/policy/documentation.md` assigns canonical ownership to the release + procedure and release notes; +- `docs/policy/architecture.md` records Linux support, best-effort macOS + development, unsupported Windows, and source-only distribution only if those + are judged durable development invariants rather than release mechanics; and +- `docs/operations.md` describes only installation or deployment consequences + relevant to operators and links to canonical CLI and release contracts. + +Current-state documentation must not describe the new release process, +`--version`, or automated validation until the corresponding behavior exists. + +## Acceptance Criteria + +- A maintainer can prepare, validate, tag, publish, and verify a source release + by following `docs/release.md` without relying on undocumented knowledge. +- Every new release has an immutable semantic-version tag and matching + checked-in release note in the tagged commit. +- The guarded candidate is clean, synchronized with `origin/main`, and passes + the documented substantive checks before tagging. +- Tag-triggered CI independently validates the published source and never + publishes binary artifacts. +- `go install` of a tagged version succeeds and `notarius --version` reports + that version; ordinary unversioned builds report `development`. +- Linux is the documented supported deployment platform, macOS has a + best-effort development build check, and Windows is explicitly unsupported. +- Downstream compatibility remains based on durable Notarius contracts rather + than the product version alone. +- Existing pre-procedure tags remain untouched and require no invented release + history. + +## Non-Goals + +- Publishing executable archives, installers, container images, checksums, + signatures, or package-manager entries. +- Supporting or cross-compiling for Windows. +- Creating or maintaining a mutable Gitea release page. +- Supporting prerelease tag syntax in the initial procedure. +- Automating version selection, release-note authorship, commits, or tag + creation. +- Retrospectively creating release notes for `v0.1.0` through `v0.3.0`. +- Treating a product version as a substitute for receipt, configuration, + prompt, or artifact schema compatibility.