Plan source-only releases
This commit is contained in:
@@ -153,7 +153,6 @@ section only after a concrete workflow, contract, and priority emerge.
|
|||||||
### Distribution And Operations
|
### Distribution And Operations
|
||||||
|
|
||||||
- Packaged release artifacts for alpha distribution.
|
- Packaged release artifacts for alpha distribution.
|
||||||
- A documented versioning and release process.
|
|
||||||
- Optional generated example-output fixtures with a regeneration procedure.
|
- Optional generated example-output fixtures with a regeneration procedure.
|
||||||
- Additional diagnostics or reporting views.
|
- Additional diagnostics or reporting views.
|
||||||
|
|
||||||
|
|||||||
428
docs/roadmap/implementation.md
Normal file
428
docs/roadmap/implementation.md
Normal file
@@ -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 <resolved-version>\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/<tag>.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@<tag>` 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.
|
||||||
281
docs/roadmap/source-releases.md
Normal file
281
docs/roadmap/source-releases.md
Normal file
@@ -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/<tag>.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/<tag>.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 ...@<tag>` 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.
|
||||||
Reference in New Issue
Block a user