Prepare the initial v0.1.0 release

This commit is contained in:
2026-10-07 02:49:47 +00:00
parent dab4fdf2b3
commit 5e60fe3113
10 changed files with 89 additions and 1198 deletions

View File

@@ -10,6 +10,9 @@ delivery are documented. ReleaseKit does not declare binary deliverables. The
[product roadmap](docs/roadmap/releasekit.md) records remaining adoption and
deployment work.
See the [v0.1.0 release note](docs/releases/v0.1.0.md) for the initial baseline
and installation commands.
Run the offline Go test suite from the repository root with:
```sh

View File

@@ -152,8 +152,8 @@ Use the maintained [tag-delivery workflow](../../examples/woodpecker/tag-deliver
in the consumer repository's `.woodpecker/` directory. Set `GO_IMAGE` to an
image with Go 1.25 or newer, Git, and a Go version compatible with the consumer
module. Replace `RELEASEKIT_VERSION` with an immutable ReleaseKit revision or
published version. The example deliberately leaves this deployment pin as a
placeholder. Configure the Woodpecker repository secret
published version. The example selects the initial `v0.1.0` baseline; update
that pin when adopting a later release. Configure the Woodpecker repository secret
`releasekit_gitea_token`; the template maps it to `RELEASEKIT_GITEA_TOKEN` only
for the delivery step. The repository needs a `delivery` profile. Page-only and
binary behavior both use this template; the profile's build target list selects

View File

@@ -2,7 +2,7 @@
**Base Policy Version:** 1.8
**Last Updated**: 2026-10-05
**Last Updated**: 2026-10-07
**Upstream Source:** [oss.md](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/oss.md)
@@ -53,7 +53,7 @@ provides texts to copy for applicable licenses and their companions.
## Project Licensing
ReleaseKit's selected grant is LGPL version 3 or later, recorded in
[COPYRIGHT](../../COPYRIGHT). It applies to the library and a future release
[COPYRIGHT](../../COPYRIGHT). It applies to the library and release
executable. Adapted policy documents, agent orientation, and the policy reading
guide retain their CC-BY-SA-4.0 scope as identified there and in the
[attribution document](../oss/attribution.md).

View File

@@ -2,7 +2,7 @@
**Base Policy Version:** 1.4
**Last Updated**: 2026-10-05
**Last Updated**: 2026-10-07
**Upstream Source:** [release.md](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/policy/release.md)
@@ -16,10 +16,10 @@ The repository-specific commands belong in `docs/release.md`. Historical release
summaries belong in `docs/releases/`. The procedure must agree with the adopted
policy and link to it rather than introduce additional release requirements.
This policy governs releases of ReleaseKit itself. Consumer release capabilities
are designed in the [product roadmap](../roadmap/releasekit.md) and acquire exact
public contracts when implemented. ReleaseKit's source publication command and
maintainer runbook are implemented; no ReleaseKit release has been published.
This policy governs releases of ReleaseKit itself. Go declarations and GoDoc
own supported consumer API contracts; the [product roadmap](../roadmap/releasekit.md)
records planned adoption and deployment work. The maintainer runbook describes
ReleaseKit's implemented source publication and hosted-page delivery procedure.
## Release Model And Completion
@@ -121,10 +121,9 @@ publish builds, verify the required build targets. Select those targets for
the project's actual support commitments; native testing on each platform
and access to particular hardware are not default release prerequisites.
The default suite and its runnable command will be established with the Go
implementation. Documentation adoption checks validate this change; they do not
create permanent release gates. ReleaseKit's source-only deliverable adds no
binary target matrix.
The publication command runs the standard offline Go test suite, followed by
any additional product checks. The [maintainer runbook](../release.md) owns its
invocation. ReleaseKit's source-only deliverable adds no binary target matrix.
Additional gates must address a concrete risk that the existing checks do not
adequately cover. Do not automatically require linting, race testing, module

64
docs/releases/v0.1.0.md Normal file
View File

@@ -0,0 +1,64 @@
# ReleaseKit v0.1.0
## Summary
ReleaseKit's initial release provides an opinionated Go library and executable
for candidate validation, annotated source-tag publication, version injection,
selected-target builds, and Gitea release delivery.
The root `releasekit` facade owns release orchestration. The separate `buildinfo`
facade supplies lightweight runtime version access. Both belong to one Go module
with a Go 1.25.0 minimum language version.
## Capabilities
- Run the standard offline Go test suite once, followed by optional
product-specific checks and selected-target build verification.
- Publish the exact annotated tag for a validated candidate already on
authoritative `main`, with bounded recovery after failed or ambiguous pushes.
- Cross-build selected Go targets with shared version injection, artifact names,
digests, and a native version smoke check. Source-only projects select no
binary targets.
- Deliver committed release notes and declared assets to Gitea, preserving
existing content and reporting partial, conflicting, and uncertain outcomes.
- Use one managed build-and-deliver operation or supply retained prebuilt
artifacts for retries and separate build/delivery environments.
- Prepare tagged CI checkouts and dependencies through the shared `ci-deliver`
command and maintained Woodpecker workflow.
See the [CLI contract](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/docs/cli.md),
[configuration reference](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/docs/config.md),
[consumer delivery guide](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/docs/consumers/delivery.md),
and [runtime version guide](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/docs/consumers/runtime-version.md)
for supported behavior.
## Adoption and compatibility
Consumers can select this initial baseline with:
```sh
go get gitea.maximumdirect.net/eric/ReleaseKit@v0.1.0
go install gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@v0.1.0
```
Profiles declare product identity, additional checks, selected binaries and
targets, and a Gitea destination. Applications obtain their embedded version
through `buildinfo.Version()`.
For consumers experimenting with earlier development revisions, rename the
`ReleaseRequest.Validate` callback to `AdditionalChecks` and remove repeated
standard-suite commands from profile `checks`. `DeliveryRequest.Build` now
accepts a `*BuildSpec` for managed builds; use `Prebuilt` for an existing
`BuildResult`.
Compatibility follows the [release policy](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/docs/policy/release.md): before
v1.0.0, minor releases may change documented contracts with migration guidance;
patch releases preserve contracts within their minor line.
ReleaseKit's deliverables are this immutable source tag and the hosted page
containing this complete note. Consumer migration and live Woodpecker deployment
remain adoption work tracked in the [product roadmap](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/docs/roadmap/releasekit.md).
[COPYRIGHT](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/COPYRIGHT) |
[LICENSE](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/LICENSE) |
[ATTRIBUTION](https://gitea.maximumdirect.net/eric/ReleaseKit/src/tag/v0.1.0/docs/oss/attribution.md)

View File

@@ -1,416 +0,0 @@
# ReleaseKit pre-release audit
Date: 2026-10-06. Reviewed source: `536a57916f6565ae8194c4563577dfcebd6cfb69`.
Status: historical review evidence and selected target direction for the
[implementation plan](implementation.md).
Audience: maintainers deciding the shared release standard before `v0.1.0`.
## Assessment
ReleaseKit's practical goals are to minimize application-owned release code,
duplication across the suite, and the time developers spend on release processes.
Shared conventions serve these goals by giving routine decisions one owner.
Applications supply product facts and product-specific checks; ReleaseKit owns
the procedure, sensible defaults, and recovery guidance.
Evaluate recommendations by the application code they remove, the shared logic
they consolidate, and the recurring decisions they eliminate. Standardization,
configuration options, and diagnostic detail are useful when they reduce that
work. Keep routine release decisions inside ReleaseKit.
The core direction is sound. Retain the publication/delivery separation, narrow
public facades, standard artifact naming, version injection, and content-aware
retries. Fix the reproduced validation and recovery defects in F1–F2 before
`v0.1.0`. Treat F3 as a focused improvement to internal build defaults.
Build-environment reproducibility, hardware-specific configurability, and
extensive build inspection are outside the product's optimization goals. Use the
available compatible Go toolchain and shared baseline settings. Evaluate new
configuration and deployment machinery by the application code and developer
work they save. Different toolchains may produce different bytes; existing
published content remains protected by digest comparison.
The implementation covers most mechanics in the [product roadmap](releasekit.md).
Representative adoption should demonstrate the
[architectural success criteria](../policy/architecture.md#success-criteria)
through deleted release code, fewer duplicated checks, and fewer routine decisions.
F4–F6 identify opportunities to centralize validation, delivery, and CI setup.
The existing source transaction supports these goals. Annotated tags preserve
the checked-in note and provide an exact object for recovery. Requiring the
candidate on authoritative `main` keeps branch publication in preparation.
Separate delivery lets source publication finish independently of hosting.
Consumer migrations should adopt this common process and retain product identity,
target selection, compatibility decisions, and product-specific checks.
## Scope and evidence
Reviewed the development guide; agent, architecture, testing, documentation, and
release policies; facade ADR; roadmap; public declarations; CLI/configuration
and consumer guides; publication, build, delivery, Git and Gitea implementations;
and their relevant tests and workflow examples. The
[release policy](../policy/release.md) governs ReleaseKit's own releases.
The facade and integration contracts define consumer behavior.
Also inspected the release scripts, module declarations, and available delivery
YAML in the six sibling projects named by the roadmap. This read-only sample
informed the assessment of adoption needs.
Existing extra checks should be retained according to their product-specific value.
For example, PromptKit has product-specific executable examples, whereas
Narratio currently requires Go 1.26 and several peers require Go 1.25.5.
Validation on Linux/amd64 with Go 1.26.8:
- `GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go test -mod=readonly -count=1 ./...`
passed on the reviewed checkout.
- `go run ./internal/apicheck` passed.
- Isolated probes against an archive of the reviewed commit reproduced F1–F3
below. They used temporary consumer repositories and local bare Git remotes.
The investigative probes ran in a disposable checkout. Their setup and outcomes
are recorded with each finding for future regressions. Validation covered local
fixtures on Go 1.26.8. Live Gitea/Woodpecker integration, published-module
installation, and minimum-Go-1.25 compatibility remain unverified. These results
belong to the original source review; this revision updates its recommendations.
## Goal coverage
| Goal | Assessment and evidence |
| --- | --- |
| One standard source-publication transaction | Substantially implemented in [Publish](../../internal/publish/publish.go): captured candidate, authoritative `main`, annotated tag, exact object/ref push, and bounded recovery. F2 is a correctness exception. |
| One validation of the intended candidate | Callback/default validation plus mutable-state rechecks are implemented in [candidate](../../internal/candidate/check.go). F1 can silently narrow the default suite; F4 concerns the selected customization model. |
| Consumer-selected binaries or source-only releases | [Build](../../internal/build/build.go) supports target pairs and empty sets. Source-only delivery creates no binary manifest. This is the right distinction. |
| Shared runtime version, build flags, naming, and smoke check | Implemented through [buildinfo](../../buildinfo/version.go), the builder, and external consumer build tests. F3 identifies an opportunity for predictable internal defaults. |
| Immutable hosted contents and recoverable partial delivery | [Delivery](../../internal/delivery/delivery.go) and [Gitea](../../internal/gitea/) compare notes and asset bytes, reject conflicts, and add missing assets. F7 identifies an outcome-reporting inconsistency. |
| Public contract ownership and small runtime dependency graph | Root and runtime facades follow [ADR 0001](../adr/0001-public-facade.md); compiled boundary checks pass. Keep these boundaries. |
| Thin application integration and less repeated infrastructure | Representative consumer adoption remains to be evaluated. F5–F6 identify remaining orchestration and setup duplication. |
| Ready deployment path | Prepared templates and local fixtures exist. Immutable deployment pins, credentials, activated workflows, and live verification remain explicitly open in the roadmap. |
## Findings
### F1 — High: ambient Go flags can turn candidate validation into a false pass
**Evidence.** `runDefaultValidation` in
[internal/candidate/check.go](../../internal/candidate/check.go) controls module
network access, workspace discovery, and toolchain selection, but inherits
`GOFLAGS`. The default command supplies `-mod=readonly -count=1`; neither flag
cancels a test-name filter. Configured checks also inherit the environment through
[RunChecks](../../cmd/releasekit/internal/cli/config.go). ReleaseKit's own
[profile](../../releasekit.json) explicitly supplies the test command without
controlling `GOFLAGS`.
**Reproduction.** Create a clean `main` fixture with a matching committed note
and one `TestFails` that calls `t.Fatal`. `Check` with no callback fails as
expected. Set `GOFLAGS=-run=^$` and invoke the same operation against the same
commit: it returns nil and reports `[no tests to run]`.
The [Go command documentation](https://pkg.go.dev/cmd/go#hdr-Environment_variables)
confirms that `GOFLAGS` supplies defaults to commands that recognize its flags.
**Consequence.** A normal developer setting used for focused testing can cause a
release to pass after skipping the default suite. The reproduction uses an
unchanged committed candidate and an ordinary shell setting.
**Recommendation.** Make the standard validation command own its effective Go
flags and host target, including values supplied through Go's persistent
configuration. Preserve caches and legitimate dependency preparation settings.
Share internal Go-environment handling where the semantics match. Preserve
the settings appropriate to native tests and static release builds separately.
Apply the same baseline to ReleaseKit's own profile. Retain a regression showing
that a failing test remains effective under an ambient filter. F4 and Design
Choice 1 describe how product-specific checks compose with this baseline.
### F2 — High: automatic push recovery can query a different endpoint and report false absence
**Evidence.** [reconcilePush](../../internal/publish/publish.go) calls
`Endpoint.QueryTag` using the captured URL and command-scoped remote.
[QueryTag](../../internal/git/tag.go) runs the query directly.
[Resolve/Recheck](../../internal/git/remote.go) call `verifyScopedURLs` before
publication. Git still applies current URL rewrite configuration to the captured
literal URL. The manual recovery instructions in
[the runbook](../release.md#resolve-failures) already require a URL-equality check.
The automatic path lacks the equivalent check.
**Reproduction.** In a temporary publication fixture, wrap Git so the actual tag
push succeeds, then add a local `url.<empty-bare-repository>.insteadOf` rule for
the captured endpoint and return exit 77 to simulate a lost acknowledgment.
`Publish` returns `state=not_published`, `phase=reconciliation`, and says the
authoritative tag is absent. Direct inspection of the original bare repository
shows the exact tag object returned in `PublicationResult` is present.
**Consequence.** The result gives incorrect recovery advice after an ambiguous
push. It converts a query to the wrong endpoint into proof that the intended
endpoint lacks the published tag. This contradicts the existing recovery
contract for the authoritative endpoint.
**Recommendation.** Within the existing bounded recovery context, verify that the
captured endpoint still resolves to itself before the one authoritative tag
query. If verification fails, preserve the push error and local tag and return
`unknown`. Keep recovery bound to the captured endpoint. Cover the
successful-publication/false-absence reproduction and ordinary recovery against
an unchanged endpoint. Preserve successful push as the completion point.
### F3 — Internal improvement: ambient CPU settings change binary compatibility
**Evidence.** `goEnvironment` in [internal/build/build.go](../../internal/build/build.go)
standardizes several Go settings and inherits architecture feature variables,
`GOEXPERIMENT`, and the persistent Go environment file.
**Reproduction.** Build the same committed consumer and `v1.2.3` for
`linux/amd64` twice, once with `GOAMD64=v1` and once with `GOAMD64=v2`.
Both builds succeed with `SourceVerified=true` and the filename
`fixture-v1.2.3-linux-amd64`. Their SHA-256 digests differ, and `go version -m`
records the respective feature levels. Go documents these as different target
microarchitecture requirements in its
[environment reference](https://pkg.go.dev/cmd/go#hdr-Environment_variables).
**Consequence.** A developer's ambient CPU setting can narrow a binary's hardware
compatibility. Different build inputs can also produce a digest conflict during
a delivery retry. Existing digest comparison correctly preserves published bytes.
The practical benefit of addressing this finding is predictable hardware
compatibility with fewer settings for application developers to manage.
**Recommendation.** Use ordinary baseline CPU settings and shared build flags
internally, with the available compatible Go toolchain. Control incidental
settings that affect expected compatibility or validation. Keep the application
profile focused on its package, binary name, and targets. Exact toolchain
pinning and detailed build metadata remain optional operational choices.
When a retry requires the original bytes, preserve and reuse those artifacts.
Design Choice 2 compares local toolchain use with a centrally maintained build
environment for consumers that benefit from shared setup.
### F4 — Design priority: adding a custom check replaces the entire standard suite
**Evidence.** [CLI routing](../../cmd/releasekit/main.go) installs a validation
callback whenever `checks` is nonempty. [Validate](../../internal/candidate/check.go)
then skips its default test command. This agrees with the
[configuration contract](../config.md), and the Go API deliberately permits a
replacement `Validate` callback.
**Consequence.** Adding one product-specific example check requires the consumer
to remember and reproduce the standard test command, environment, and ordering.
The profile becomes a small release program that repeats shared policy. Migrating
to built-in tests requires removing their invocation from existing custom scripts
to preserve one suite run.
**Recommendation.** Run the shared offline suite once, followed by optional
product-specific checks. Move redundant suite invocations out of consumer scripts.
Retain checks for actual product behavior, such as PromptKit's examples. Add
alternative test-invocation settings when a concrete consumer requirement
justifies them. This choice changes the current customization contract; Design
Choice 1 records the replacement-callback alternative.
### F5 — Design priority: the CLI owns reusable tagged-build delivery orchestration
**Evidence.** [runDelivery](../../cmd/releasekit/main.go) chooses a temporary
output directory, invokes the public builder, converts receipts, and then calls
`Deliver`. The [public delivery request](../../delivery.go) accepts an already
produced `BuildResult`. A Go consumer wanting the normal build-and-deliver
operation must reproduce orchestration already implemented by the CLI. The
default CLI path also builds and runs the native smoke executable
before `Deliver` verifies that HEAD matches the selected local tag.
**Consequence.** Temporary storage, build sequencing, tagged-source preflight,
and cleanup have more than one potential owner. An invalid tagged checkout can
consume a complete cross-build before it is rejected. The CLI owns domain coordination
alongside its parsing, presentation, and exit-status responsibilities.
**Recommendation.** Put the ordinary verify-tagged-source, build-selected-targets,
and deliver sequence behind the orchestration facade. Verify the local tagged
source before expensive compilation, then retain the necessary checks before
remote effects. Let the CLI adapt JSON, credentials, and output to that operation.
Use the same build declaration for candidate validation and delivery. Support
caller-provided builds for concrete needs such as retrying with retained
artifacts, as discussed in Design Choice 3. Keep separate building useful for
local development. The ordinary consumer workflow should complete delivery in
one invocation; advanced artifact handoffs can use private coordination data
when needed.
### F6 — Adoption priority: shared deployment still depends on copied mechanics
**Evidence.** The original source-only and binary templates repeated
fetch/checkout guards, local exclusions, cache setup, and tool installation;
they are now consolidated in the maintained
[tag-delivery template](../../examples/woodpecker/tag-delivery.yml). The binary
template added an explicit build/receipt/deliver sequence even though the CLI
already supports combined delivery. ReleaseKit's
[own workflow](../../examples/woodpecker/releasekit-source-delivery.yml) has a
separate first-release bootstrap. Consumer pins remain placeholders as documented.
**Consequence.** Copied CI mechanics require maintenance in each consumer and
can drift. A shared installation and update convention would simplify local
publication and CI delivery.
**Recommendation.** Provide one maintained integration entry point and one
default delivery sequence for source-only and binary profiles. Consumers select
the ReleaseKit version, supply product settings, and provision credentials.
Centralize installation and update instructions. Use versioned source
installation for the shared CI command. Evaluate a maintained image by the
additional setup and maintenance effort it saves.
Keep dependency preparation separate from offline validation/builds. A split
build/delivery flow remains useful for an actual credential boundary or artifact
handoff. See Design Choice 4 for packaging alternatives.
The original `TestWoodpeckerDeliveryCommandSequences` and the ReleaseKit
workflow test reconstructed workflow commands, so YAML drift could leave the
tests green. The maintained tag template and ReleaseKit's bootstrap workflow
are now exercised from their command blocks by local Git/HTTP fixtures. The Go
bootstrap shim verifies template arguments while mapping the pinned module
invocation to the test executable; it does not verify published-module
availability. Real installation and live Woodpecker execution remain
deployment work.
### F7 — Medium: delivery asset classifications overlap inconsistently
**Evidence.** In [UploadMissing](../../internal/gitea/upload.go), a failed
reconciliation list adds an asset to `Uncertain` while leaving it in `Pending`.
The `AssetMissing` reconciliation branch does the same for an unresolved write;
the default/unverifiable branch removes it from `Pending`. A reconciled conflict
can also remain pending. The existing
`TestUploadMissingReportsUnknownWhenReconciliationReadFails` in
[upload_test.go](../../internal/gitea/upload_test.go) explicitly expects the
same asset in both pending and uncertain collections.
**Consequence.** Overlapping categories require special handling by consumers.
The CLI can present one file as both pending and uncertain, while a
slightly different failure reports it only as uncertain. The overall unknown
state remains conservative. Consistent categories would simplify recovery
reporting and automation.
**Recommendation.** Prefer mutually exclusive current-outcome categories:
confirmed matching, uploaded, known pending, conflicting, and uncertain. Move an
asset out of pending when its outcome becomes uncertain or conflicting, and
clarify the facade GoDoc. Design Choice 5 records the alternative superset
interpretation.
### F8 — Maintainability: artifact rules have several implementation owners
**Evidence.** Filename construction occurs in `artifactFilename` in
[the builder](../../internal/build/build.go), `receiptArtifactFilename` in
[CLI receipt handling](../../cmd/releasekit/internal/cli/receipt.go), and
`declaredBuildAssets` in [delivery](../../internal/delivery/assets.go).
Target normalization and filename-component validation are also repeated across
these boundaries. CLI receipt handling carries substantial domain validation
alongside JSON serialization. Build invocation uses its own `exec.CommandContext`
path while default validation uses [process.Run](../../internal/process/process.go),
with independently constructed Go environments.
**Consequence.** A change to target identity, naming, or build settings can leave
the builder, receipt reader, and delivery validator disagreeing. F1 and F3 show
why divergent Go-environment ownership matters beyond cosmetic duplication.
**Recommendation.** Give internal build/artifact rules one owner and reuse them
from receipt and delivery adapters. Share Go invocation/environment construction
where the semantics match. Keep the explicit facade conversions required
by the ADR. Focus refactoring on the small internal helpers that own these rules.
## Target state
Retain the existing source transaction: committed stable-version note, clean
`main`, candidate already on authoritative `main`, one validation, selected-target
build verification, exact annotated-tag publication, and bounded recovery.
Source publication finishes independently of hosted delivery. Keep additive,
content-checked delivery and lightweight runtime version access.
Make ordinary integration a versioned tool invocation plus a small product
profile and credential provisioning. The profile supplies product identity,
selected binaries and targets, delivery destination, and product-specific checks.
ReleaseKit owns the standard suite, routine build settings, delivery sequence,
and recovery reporting. Product developers choose versions and write
compatibility notes. Evaluate each proposed setting by the work it saves them.
The [implementation plan](implementation.md) owns the stages, API changes,
regression coverage, and completion criteria needed to reach this target.
Representative adoption should demonstrate fewer scripts, duplicated tests,
setup steps, and recurring release decisions.
Feature expansion should follow demonstrated consumer needs and measurable
reductions in application maintenance or developer effort.
## Design Choices
The implementation plan selects the recommended directions below for the
upcoming sprint. Alternatives record the tradeoffs for future consumer needs.
These choices describe the target behavior; current contracts change as their
implementation lands.
### 1. Should product checks supplement or replace standard validation?
**Selected direction:** Run the shared offline Go suite once, followed by optional
product-specific checks. ReleaseKit owns the command and its routine environment
settings. Migrate repeated suite invocations out of application scripts. Add
alternative invocation settings when an actual consumer requirement establishes
their value. An application adding an example check should declare that check
and receive the standard suite automatically. This gives developers one ordinary
validation path to understand.
**Viable alternative:** Keep a replacement callback or complete validation
command for products with unusual test layouts. This is a simple composition
boundary and can accommodate existing product test infrastructure. It assigns
more release responsibility to the application, so its value depends on the
specific consumer need.
### 2. How should ReleaseKit choose build settings?
**Selected direction:** Use the available compatible Go toolchain, ordinary
baseline CPU settings, and shared build flags. Handle incidental settings internally
so developers can rely on the selected target's expected compatibility. Keep
application configuration small. Toolchain-dependent byte differences are
acceptable; digest checks preserve existing published content, and retained
artifacts support retries requiring the same bytes. ReleaseKit can own baseline
settings internally while applications declare their packages and targets.
**Viable alternative:** A shared CI image can supply a centrally selected Go
version and build environment when this makes installation and support easier.
Maintainers own image updates; applications use the shared integration. This is
useful where a common environment reduces operational work. Its value should be
measured against image maintenance and the suite's differing Go requirements.
Explicit hardware variants can be added for a demonstrated product need.
### 3. Should the library own build-and-deliver, or accept only completed builds?
**Selected direction:** Provide one facade operation for tagged-source verification,
selected-target builds, temporary storage, checksums, uploads, and cleanup.
Use it from the CLI so both interfaces share the procedure. Retain separate
building for local development and support prebuilt delivery where a concrete
handoff or retry requirement justifies it. Routine delivery should require one
invocation, with ReleaseKit managing the artifact lifecycle. This minimizes
consumer orchestration code.
**Viable alternative:** Keep separate build and delivery primitives with a
maintained composition helper. This suits consumers that require credential
isolation between stages or need to retain artifacts for later delivery. Those
consumers accept responsibility for the artifact lifecycle in exchange for the
operational separation they need.
### 4. How should the shared executable and CI integration be distributed?
**Selected direction:** Choose the simplest maintained entry point for installation,
updates, and delivery. Use versioned source installation and a shared CI delivery
command. The command prepares the tagged checkout, reads its product profile,
prepares dependencies for selected binaries, and invokes ordinary facade delivery.
Centralize reusable setup and provide one clear upgrade procedure. Applications
select a ReleaseKit version and supply product settings and credentials; shared
integration owns routine setup.
Assess packaging by the consumer code and recurring developer work it removes.
**Viable alternative:** Publish a maintained CI image containing ReleaseKit and
a compatible Go/Git environment when it substantially reduces setup. The image
provides a ready-to-run integration and centralizes environment maintenance.
It also creates an image publication and update responsibility, which should be
reflected in the release procedure. Either packaging choice should give
applications a small configuration and a routine invocation.
### 5. How should delivery results support simple recovery?
**Selected direction:** Use exclusive outcome categories: matching, uploaded, known
pending, conflicting, and uncertain. Present ordinary callers with completion or
a clear failure and recovery instruction. Keep asset details available for
diagnostics. Derive recovery guidance centrally so each application can present
the result directly. Consistent categories simplify implementation and
interpretation.
**Viable alternative:** Pending includes every unfinished declaration, with
conflicting/uncertain as diagnostic subsets. This can simplify a progress UI
when defined explicitly and applied in every branch. Consumers must then
subtract blocked subsets before deriving retry work. Apply the chosen
meaning consistently across all outcomes.

View File

@@ -1,598 +0,0 @@
# ReleaseKit audit implementation plan
Status: All implementation stages complete.
Baseline: `e4be7fa` (2026-10-06). The [audit](audit.md) records the evidence,
product goals, and selected direction. This document owns implementation order
and completion criteria for that work.
## How to execute this plan
Implement one numbered stage per prompt, in order. Each stage includes its
production change, relevant tests, and current-contract documentation. Leave the
repository compiling and its checks passing at each stage boundary. Record
completed stages here with a concise validation result; report the commit
identifier in the stage completion response. Read
[development guidance](../development.md) and its applicable policies at the
start of each stage.
Use the [agent policy](../policy/agents.md), [architecture
policy](../policy/architecture.md), [testing policy](../policy/testing.md), and
[documentation policy](../policy/documentation.md). Discover current symbols
through the codebase graph, then inspect their callers and tests before editing.
The paths below locate the baseline; internal names may evolve during the work.
Use ordinary functions and existing internal packages where their ownership
fits. Public named types remain facade-owned with explicit internal conversions.
For each stage, run focused behavioral tests for its changed responsibilities.
Then run the existing repository checks from the root:
```sh
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go test -mod=readonly -count=1 ./...
GOTOOLCHAIN=local GOPROXY=off GOSUMDB=off go run ./internal/apicheck
```
Prepare dependencies before these offline checks when needed. Review changed
GoDoc, examples, local documentation links and fragments, and `git diff --check`.
Reuse successful checks for unchanged content. Commit each completed stage
under the agent policy. These implementation checks serve the development
workflow.
## Decisions for this sprint
These choices resolve the audit's design alternatives for implementation:
- Candidate validation runs the standard offline Go suite once, then optional
product checks, then selected-target build verification. Rename the Go
callback to `AdditionalChecks`; JSON retains `checks` with additive semantics.
- ReleaseKit uses the available compatible Go toolchain, internal baseline CPU
settings, and shared build flags. It controls incidental flags and persistent
Go settings while preserving operational configuration such as caches.
- `Deliver` accepts a build declaration and owns temporary build output,
checksums, uploads, and cleanup. An explicit prebuilt path retains original
artifacts for retries and supports separated build/delivery environments.
- Delivery asset categories are disjoint observations: matching, uploaded,
known pending, conflicting, and uncertain. Existing overall delivery states
and content-preservation rules remain authoritative.
- A versioned source-installed command is the initial shared CI entry point.
Add `ci-deliver` for explicit CI checkout and dependency preparation followed
by the same facade delivery operation. Ordinary `deliver` remains suitable
for an already prepared checkout. CI images remain an operational option.
- Shared artifact rules and Go execution settings have small internal owners.
Application profiles continue to declare product facts and additional checks.
The callback and delivery request changes are deliberate pre-release API
changes. Update all in-repository callers and their canonical documentation in
the corresponding stage. The initial release note should describe the final
interfaces and migration impact when that release is prepared.
The sprint preserves the existing source transaction, successful-tag-push
completion point, bounded recovery, content-aware retries, standalone `Build`,
and lightweight `buildinfo`. Build observations and private receipts retain
their existing source-eligibility meaning. Toolchain-dependent byte differences
remain acceptable. Build identity remains an observation of the checked source
and produced files under the existing contracts. Live deployment and sibling
repository migrations remain separate adoption work in the
[product roadmap](releasekit.md).
## Stage 1 — Keep ambiguous-push recovery on the captured endpoint
**Covers:** F2. **Primary owners:** `internal/git/tag.go`,
`internal/git/remote.go`, `internal/publish/publish.go` and their tests.
1. Before `Endpoint.QueryTag` performs its remote read, reuse
`verifyScopedURLs` with the captured endpoint and command-scoped configuration.
Verify that the captured URL still resolves to itself. Use the existing
reconciliation context and timeout for both verification and the remote read.
2. Treat verification failure as unreadable authoritative state. Preserve error
identity through wrapping so `reconcilePush` reports `unknown`, retains the
local tag, and preserves the original push failure for diagnosis.
3. Keep the captured endpoint as recovery's authority. The local resolution
check precedes the existing single remote tag query. Preserve exact tag-object
and peeled-commit comparison and successful push as the completion point.
4. Update relevant recovery GoDoc and internal guidance to explain the
automatic URL-resolution check. Keep the manual recovery runbook consistent.
**Completion evidence:** Extend the existing local Git publication fixtures with
F2's lost-acknowledgment reproduction: actually publish the tag, install a URL
rewrite to an empty bare repository, then report a push error. Recovery must
return unknown and preserve the tag/error; direct inspection of the original
remote must find the intended object. Existing unchanged-endpoint success,
absence, conflict, and unreadable-recovery tests continue to pass. Test the
behavior through publication; avoid a second copy of the full recovery matrix.
**Completed:** Recovery now verifies the captured URL before its one tag query.
The rewrite reproduction returns unknown, preserves the local tag and both
errors, and confirms the object on the original remote. Focused publication
tests, the full offline suite, API boundary checks, and documentation whitespace
checks pass.
## Stage 2 — Own effective Go settings for validation and builds
**Covers:** F1, F3, Go-environment portion of F8. **Primary owners:**
`internal/candidate/check.go`, `internal/build/build.go`, `internal/process/`,
and a small new `internal/gotool` package.
1. Put effective Go-environment construction and common invocation behavior in
`internal/gotool`. Reuse the existing subprocess boundary for context,
working directory, output, and error handling. Support native validation and
static target builds as distinct modes of the same implementation.
2. Account for both the process environment and values from Go's persistent
environment file. Resolve effective Go configuration with the installed Go
command under local toolchain selection and a controlled `GOFLAGS`. Ensure
configuration discovery itself tolerates the ambient settings being replaced;
an experiment override used only for discovery must not become the build
default. Carry effective operational settings into child environments, then
use `GOENV=off`
there so removed settings cannot reappear from the persistent file. Retain
ordinary process variables and effective cache, module-cache, temporary,
tool-location, and native C-tool settings. Keep informational `go env` output
separate from configuration when constructing child environments.
3. Own `GOFLAGS`, `GOWORK`, `GOTOOLCHAIN`, module-network settings, target
selection, experiment selection, and architecture-feature settings. Standard
validation uses `go test -mod=readonly -count=1 ./...`, host OS/architecture,
`GOWORK=off`, `GOTOOLCHAIN=local`, `GOPROXY=off`, `GONOPROXY=none`, and
`GOSUMDB=off`. Resolve the Go host target independently of ambient cross-build
settings. Native tests retain native Go cgo behavior and explicit native
C-tool configuration; release builds retain `CGO_ENABLED=0`.
4. Clear ambient experiments and architecture tuning for the child so the
selected Go toolchain supplies ordinary baseline defaults. Handle the Go
feature variables for supported toolchains, including `GOAMD64`, `GOARM`,
`GOARM64`, `GO386`, `GOMIPS`, `GOMIPS64`, `GOPPC64`, `GORISCV64`, and `GOWASM`.
Clearing must take effect for persisted values as well. Retain the existing
release flags, linker injection, target selection, and native version smoke
check. Keep these settings internal; the profile needs no new tuning fields.
5. Route default validation, build toolchain/host queries, target compilation,
and native smoke-build compilation through the shared owner. Preserve useful
compiler diagnostics and cancellation. Custom product commands retain their
explicitly selected arguments and environment overlays.
6. Update the build and check consumer guides and relevant GoDoc with the
supported behavior: shared baseline settings and the available compatible
toolchain. Exact internal environment construction belongs in internal docs.
**Completion evidence:** A genuinely failing fixture test still fails with
`GOFLAGS=-run=^$` supplied through either the process or a temporary Go env file.
An ambient cross-target setting still results in host-native validation. Extend
existing build fixtures to demonstrate that ambient/persisted `GOAMD64=v2` and
experiment settings do not alter the selected baseline build settings. Inspect
build metadata where useful; identical binary bytes are unnecessary evidence.
Use a temporary configured cache to demonstrate that persistent cache choices
survive. Preserve existing version injection, empty-target, cancellation, and
partial-build behavior. Fixtures use temporary Go configuration and never edit
the developer's persistent settings.
**Completed:** Shared Go configuration now drives default validation,
toolchain/host queries, target builds, and the native smoke build. Failing
validation fixtures prove process and persistent `GOFLAGS` cannot suppress a
real test and that cross-target settings still run tests on the host. Build
metadata confirms ambient and persistent tuning are cleared, and a temporary
persistent cache is used. Focused tests, the full offline suite, API boundary
checks, and documentation whitespace checks pass.
## Stage 3 — Make product checks additive
**Covers:** F4 and ReleaseKit's own F1 exposure. **Primary owners:** `check.go`,
`publish.go`, `internal/candidate/`, CLI profile mapping and fixtures.
1. Rename `ReleaseRequest.Validate` to
`AdditionalChecks func(context.Context, Candidate) error` and update the
corresponding internal request and facade conversions. The callback keeps
the existing candidate-value ownership and error-wrapping behavior.
2. Make `candidate.Validate` always run the shared offline suite first. On
success, invoke `AdditionalChecks` once when supplied. Run selected-target
build verification after these checks through the existing orchestration.
A failure or cancellation ends the sequence and preserves its cause.
3. Retain `checks` in JSON as ordered additional commands. Map the CLI's
`RunChecks` callback to `AdditionalChecks`. Keep the existing argument-vector
and per-command environment semantics.
4. Remove repeated standard-suite commands from `releasekit.json` and example
profiles. Preserve additional checks that address actual product behavior.
Update in-repository callback callers and fixtures to provide small valid Go
modules with an effective default suite. A callback fixture must exercise
its intended callback behavior after that suite succeeds.
5. Update facade GoDoc, `docs/config.md`, `docs/cli.md`, check/publish consumer
guides, examples, and affected internal documentation. Explain migration:
rename the callback and remove standard-suite invocations from custom checks.
**Completion evidence:** Through the public facade, prove that a failed standard
suite prevents the additional callback and publication, that an additional
failure prevents publication while preserving error identity, and that a
successful publication runs the standard suite and additional checks once for
its captured candidate. Reuse existing mutation/recheck tests with the new
callback. One CLI profile test covers ordered extra commands. Keep callback
unit coverage and end-to-end suite-count coverage at distinct boundaries.
**Completed:** `AdditionalChecks` now runs after the standard offline suite in
the public check and publish flows; selected builds remain after both. The CLI
keeps ordered JSON `checks` as additional commands, and the bundled profiles no
longer repeat the standard suite. Facade tests prove suite failure stops checks
and publication, additional-check errors retain identity, and successful
publication runs both once for its captured candidate. CLI coverage verifies
ordered checks. The full offline suite, API boundary check, and documentation
whitespace checks pass.
## Stage 4 — Consolidate artifact identity and declaration rules
**Covers:** artifact portion of F8. **Primary owners:** `internal/build/`,
`internal/delivery/assets.go`, `cmd/releasekit/internal/cli/receipt.go`.
1. Add a small internal artifact-contract owner for target normalization,
filename-component validation, artifact names, and the expected declaration
for a build. Choose `internal/artifact` for these shared pure rules.
2. Move the existing rules from builder, receipt, and delivery into that owner.
Preserve accepted inputs, target order/deduplication, filenames, manifest
naming, and validation meaning. Keep build execution in `internal/build`,
hosted-content checks in delivery/Gitea, and receipt JSON/path handling in
the CLI adapter.
3. Use ordinary conversions at facade and receipt boundaries. Preserve
facade-owned public types and the current private receipt format. Consolidate
repeated declaration comparisons while retaining boundary-specific checks
for repository, commit, version, file location, and actual file contents.
4. Update the internal package inventory. Keep exact public build/result
contracts in GoDoc and private receipt lifecycle in its existing owner.
**Completion evidence:** Existing build-to-receipt-to-delivery tests retain
behavior for normalized targets, filenames, altered files, mismatched identity,
and manifests. Add only missing coverage for disagreement between these
boundaries. The API/dependency checker confirms that the shared internal owner
has not leaked through exported signatures or runtime dependencies.
**Completed:** `internal/artifact` now owns target normalization, filename
components, binary declarations, and checksum-manifest naming. The builder,
receipt adapter, and delivery validation share those rules while retaining
their build, receipt-path/file, and hosted-content responsibilities. Existing
coverage plus a mismatched delivery declaration check preserve cross-boundary
behavior. Focused tests, the full offline suite, API boundary checks, and
documentation whitespace checks pass.
## Stage 5 — Make delivery outcomes disjoint and actionable
**Covers:** F7. **Primary owners:** `internal/gitea/upload.go`, delivery result
GoDoc, CLI delivery reporting, and their tests.
1. Define the five collections as current observations for each reported asset.
`Matching` means existing matching content; `Uploaded` means confirmed upload
during this invocation; `Pending` means known missing work; `Conflicting`
means a detected conflict; `Uncertain` means unresolved state. Each asset
appears in at most one collection in a returned result.
2. In every upload/reconciliation branch, remove an asset from `Pending` when
moving it to matching, uploaded, conflicting, or uncertain. In particular,
fix failed reconciliation reads, conflicts, and unresolved writes. Later
known-missing assets can remain pending when an earlier upload stops work.
3. Preserve the existing overall delivery states and their handling of remote
writes. Early failures can return incomplete asset information. Category
exclusivity establishes no claim that every declaration has been observed.
4. Keep concise state-based recovery guidance in one CLI formatter: correct
local/preflight failures before retrying; retry partial delivery after fixing
its cause; resolve uncertain remote state before retrying; investigate
conflicting content and use a new version when source or published contents
require correction. Mention retained original artifacts when a rebuild would
conflict. Go callers use the documented overall state and asset categories.
5. Update delivery GoDoc, `docs/cli.md`, the delivery consumer guide and Gitea
integration documentation. Keep diagnostics available alongside the summary.
**Completion evidence:** Update the existing reconciliation-read-failure test
that currently expects overlap. Extend existing upload tests to cover conflict,
missing-after-ambiguous-upload, matching-after-lost-acknowledgment, and later
pending assets. Assert category exclusivity and meaningful overall state at the
upload boundary. CLI tests verify recovery meaning and exit classification
without freezing full diagnostic wording.
**Completed:** Delivery asset categories now contain disjoint current
observations, with later known-missing assets retained when an earlier upload
stops work. CLI failures include state-based recovery guidance, while GoDoc and
the delivery and Gitea guides describe category meaning and incomplete early
observations. Upload and CLI tests cover reconciliation outcomes, recovery
classification, and category exclusivity. The full offline suite, API boundary
check, and documentation whitespace checks pass.
## Stage 6 — Give the facade ownership of build-and-deliver
**Covers:** F5. **Primary owners:** `delivery.go`, `internal/delivery/`,
`internal/build/`, and existing temporary-directory helpers.
1. Change `DeliveryRequest.Build` to `*BuildSpec`. Add
`Prebuilt *BuildResult` and `Output io.Writer`. `Build` requests managed builds;
`Prebuilt` supplies an existing result. Supplying both is an invalid request
because the operation needs one artifact source. With neither, or with an
empty selected target set, ordinary delivery is page-only. Preserve the
existing handling of empty prebuilt results.
2. Implement the reusable orchestration inside `internal/delivery`; the public
facade performs conversions. Verify version, product, local tag/HEAD
agreement, checkout cleanliness, and the committed release note before
compilation. Preserve historical lightweight-tag and detached-HEAD support.
3. For nonempty `Build`, create temporary output outside the worktree using the
existing helper, invoke the shared builder, and feed its result into the
existing asset validation/delivery path. Defer cleanup for success, failure,
and cancellation. Return diagnostic progress through `Output`; managed
temporary paths have no caller-owned lifetime.
4. Before hosted writes, retain the tagged-source eligibility check and the
build-result, file-digest, and manifest checks. A checkout change during the
build must fail eligibility. Use the same captured tag commit to read the
note and validate the build. Reuse the existing builders and delivery client.
5. `Prebuilt` retains caller-owned files and existing source/identity/content
checks. Its build result declares its targets as today. The CLI continues
comparing receipts with the selected profile. This path supports original
bytes across retries; callers own retention and cleanup.
6. Keep pre-remote build/preflight failures `DeliveryNotAttempted`. Preserve
candidate identity when known, wrapped error causes, cancellation, and the
current mapping of hosted failures and partial progress.
7. Update all Go callers for the request shape. As an intermediate step, map
the CLI's current already-built result to `Prebuilt`; Stage 7 removes that
duplicate orchestration. Update delivery GoDoc and the consumer guide with
the normal `Build` path and the explicit `Prebuilt` lifecycle.
**Completion evidence:** Add facade-level tests using a real small Go consumer
and a local HTTP server for managed binary delivery and page-only delivery.
Prove invalid tagged source fails before Go compilation or hosted writes,
build failure prevents hosted writes, and managed temporary output is cleaned
on success and failure. Extend existing mutation/cancellation coverage where
needed. Preserve prebuilt retry, digest conflict, note conflict, and source
eligibility coverage. Confirm the two facades' dependency boundaries.
**Completed:** `Deliver` now owns optional managed builds, page-only requests,
and explicit prebuilt artifact delivery behind the public facade. Managed output
uses temporary storage outside the checkout and is cleaned after success,
failure, and cancellation; source and note checks precede compilation, and
eligibility is rechecked before hosted writes. Prebuilt files remain
caller-owned. Consumer and internal package guides describe these paths.
Facade-level consumer and HTTP tests cover managed upload, page-only delivery,
preflight and build failures, checkout mutation, cleanup, cancellation, and
prebuilt ownership. The full offline suite, API boundary check, and
documentation whitespace checks pass.
## Stage 7 — Route ordinary CLI delivery through the facade
**Covers:** the CLI portion of F5. **Primary owners:**
`cmd/releasekit/main.go`, CLI receipt adapters, CLI tests and documentation.
1. Change ordinary `runDelivery` to pass the configured `BuildSpec` and output
writer directly to `Deliver`. Remove its temporary-directory and standalone
build coordination. Keep profile parsing, credential lookup, presentation,
and exit-code selection in the CLI.
2. Retain `build --output` and `deliver --assets`. The latter loads and verifies
the private receipt, compares it with the selected profile, and supplies
`Prebuilt`. Keep stale-receipt invalidation and standalone build behavior.
3. Share the final CLI-to-facade delivery adapter so the CI entry point in Stage
9 can use it after preparation. Keep ordinary `deliver` free of dependency
downloading and checkout mutation.
4. Update CLI/configuration guidance and examples to make one `deliver`
invocation the normal path. Describe split build/delivery for retained bytes
and credential separation. Preserve exit statuses 0, 1, 2, and 3.
**Completion evidence:** CLI tests cover source-only and binary profiles,
preflight failure before compilation, token/profile errors, and the explicit
receipt path. Reuse Stage 6 for domain failure coverage. Confirm the maintained
ordinary command exercises the facade-owned lifecycle and reports F7's results.
**Completed:** Ordinary `deliver` now passes configured builds and progress
output directly to the public facade; the CLI retains profile, credential,
receipt, presentation, and exit-status handling. `--assets` still validates
the private receipt and supplies caller-owned artifacts. CLI tests cover
page-only and binary profiles, preflight rejection before build progress,
retained prebuilt artifacts, retry observations, and temporary-output cleanup.
The binary workflow and consumer guidance use one `deliver` invocation by
default and explain the separate `build`/`--assets` path. The full offline suite,
API boundary check, and documentation whitespace checks pass.
## Stage 8 — Add reusable CI preparation operations
**Covers:** preparation ownership in F6. **Primary owners:** a new root
`preparation.go`, `internal/git/`, `internal/gotool/`, and a small internal
preparation coordinator.
1. Add facade-owned `TaggedCheckoutRequest` with `RepositoryDir`, `Version`,
`Remote`, and `ExpectedCommit` strings, and
`PrepareTaggedCheckout(context.Context, TaggedCheckoutRequest) error`.
An empty remote selects `origin`. This is an explicit preparation operation
for disposable CI checkouts; ordinary delivery keeps its current behavior.
2. Validate the version and required expected commit before mutation. Fetch
the selected tag from the selected remote with an explicit tag refspec,
verify that its peeled commit equals the expected CI commit, detach checkout
at that commit, and verify HEAD agreement. Use the existing Git subprocess
boundary and preserve Git errors. Use ordinary checkout/fetch behavior;
conflicting local changes or tags are reported for the operator to resolve.
3. Add `PrepareBuildDependencies(context.Context, string) error`, taking the
repository directory. Internally run `go mod download` with the available
compatible local Go toolchain and workspace discovery disabled. Preparation
uses the caller's dependency-access settings, including proxy/private-module
configuration and caches. This operation is explicitly network-capable.
Keep offline test/build environments from Stage 2 distinct from preparation.
4. Keep both operations behind the root facade with internal implementations.
These two additions serve the concrete shared CI workflow and Go consumers
with the same preparation needs. Keep their API small: CI-provider variables,
JSON profile loading, credentials, and output formatting stay in adapters.
5. Add GoDoc and a short preparation section to the delivery consumer guide;
update the internal package inventory. State filesystem/network effects and
cancellation behavior. Preparation does not publish a tag or hosted content.
**Completion evidence:** Local Git fixtures verify expected-commit agreement,
wrong-tag rejection before checkout, detached checkout, and ordinary local
conflict behavior. A subprocess-boundary test verifies dependency preparation
uses the repository and preparation environment and propagates failure and
cancellation. Keep default tests offline with a local module cache or a small
Go-command fixture; no live module server is needed.
**Completed:** The root facade now exposes `PrepareTaggedCheckout` and
`PrepareBuildDependencies`. Checkout preparation fetches an explicit tag
refspec, compares the peeled commit with the expected full object ID, and
detaches only after a match; tests cover default and selected remotes, wrong
commits, conflicting local edits and tags, and input rejection before fetch.
Dependency preparation runs `go mod download` with workspace discovery off and
the local Go toolchain, preserving caller proxy, private-module, and cache
settings; subprocess fixtures verify repository selection, failure details,
and cancellation without network access. GoDoc, the delivery consumer guide,
and the internal inventory describe effects and ownership. The full offline
suite, API boundary check, and documentation whitespace checks pass.
## Stage 9 — Add the shared CI delivery command
**Covers:** the shared command portion of F6.
**Primary owners:** CLI parsing/routing, CLI command tests, `docs/cli.md`,
and `docs/config.md`.
1. Add:
```text
releasekit ci-deliver [--repo DIR] [--config FILE] [--remote NAME] --commit OID VERSION
```
Options precede the version, consistent with existing commands. Repository
and profile defaults match `deliver`; remote defaults to `origin`. The
explicit command authorizes preparation of the selected CI checkout.
2. Call `PrepareTaggedCheckout`, then load the profile from that checked-out
source, then validate the selected delivery configuration and credentials.
When the profile selects binaries, call `PrepareBuildDependencies`. Finish
through Stage 7's ordinary delivery adapter and `Deliver`. Page-only profiles
skip application dependency preparation and binary work. Read custom profile
paths under the existing CLI path rules.
3. Keep the provider adapter declarative: Woodpecker supplies `CI_WORKSPACE`,
`CI_COMMIT_SHA`, and `CI_COMMIT_TAG` as command arguments. The library and
ordinary CLI operations remain independent of Woodpecker environment names.
Preparation failures return 1; argument/profile/credential errors return 2;
final delivery uses the existing success/failure/unknown status mapping.
4. Update command usage, `docs/cli.md`, and configuration guidance for the new
entry point, its preparation effects, profile-loading order, and exit codes.
Keep ordinary `deliver` documented as operating on prepared source.
**Completion evidence:** Exercise the command with local Git/HTTP fixtures for
source-only and binary delivery. Prove the profile is read after checkout,
a wrong CI commit fails before application builds or hosted writes, and a
source-only module with unavailable dependencies still reaches page delivery.
Reuse facade tests for the individual preparation and delivery operations.
**Completed:** `ci-deliver` now prepares the tagged checkout against the
provider-supplied commit, loads the profile from that checkout, validates its
delivery settings and credential, downloads dependencies only for selected
binary targets, and finishes through the existing delivery facade. Local
Git/HTTP fixtures cover source-only and binary delivery, relative custom profile
loading, commit mismatch before Go or hosted requests, and unavailable
source-only dependencies. CLI and configuration guidance describe preparation,
provider arguments, effects, and exit statuses. The full offline suite, API
boundary check, and documentation whitespace checks pass.
## Stage 10 — Consolidate and exercise maintained CI templates
**Covers:** installation, workflow duplication, and artifact-testing in F6.
**Primary owners:** `examples/woodpecker/`, CLI workflow tests, installation
instructions, and the product roadmap.
1. Select versioned source execution as the default bootstrap:
`go run gitea.maximumdirect.net/eric/ReleaseKit/cmd/releasekit@PIN ci-deliver ...`.
`PIN` is an immutable ReleaseKit revision or published version. Applications
choose a compatible Go/Git image and provision the delivery token. The shared
command owns checkout checks, conditional dependency preparation, and delivery.
The normal Go caches suffice; optional CI cache mounts remain deployment
configuration. Document `go install ...@PIN` for a locally retained executable
and one upgrade procedure based on changing the selected version.
2. Consolidate source-only and binary Woodpecker templates into one maintained
`examples/woodpecker/tag-delivery.yml`, with the product profile selecting
page-only or binary behavior. Remove the two superseded templates and repair
their links. Retain the distinct first-release bootstrap in
`releasekit-source-delivery.yml`, since ReleaseKit's own first source release
must build its tool from the tagged source. Simplify it around the shared
command where this preserves that bootstrap.
3. Replace tests that reconstruct the workflow commands with checks tied to the
maintained artifact. Use a small extractor for the template's one command
block and execute it with controlled CI variables, local Git/HTTP fixtures,
and a Go bootstrap shim that maps the pinned remote tool invocation to the
CLI built from the test checkout. Validate the module/command/version
arguments in the shim. Apply the template's matrix substitutions and
Woodpecker dollar escaping before shell execution. Keep the template subset
simple enough for a small test helper; a general YAML runner is unnecessary.
4. Document bootstrap requirements, token provision, compatible Go selection,
optional caches, dependency preparation, and the version upgrade procedure.
Align `releasekit.md`'s remaining adoption work with source installation;
identify live deployment and the real immutable pin as remaining work.
**Completion evidence:** Execute the actual maintained command block for both
source-only and binary fixture delivery. A repeated invocation preserves
matching remote content. The bootstrap shim proves template wiring, not
published-module availability. Record that distinction and retain real
installation/live Woodpecker verification as deployment work.
**Completed:** Source-only and binary consumer delivery now share one
profile-driven `tag-delivery.yml` using versioned `go run ... ci-deliver`; the
duplicated templates were removed. ReleaseKit's separate first-source workflow
still builds its CLI from tagged source and then uses `ci-deliver`. CLI workflow
tests extract and execute the maintained command blocks with matrix
substitution, Woodpecker dollar escaping, local Git/HTTP fixtures, and a Go
bootstrap shim. Both profiles deliver successfully twice, preserving matching
pages and binary assets. The shim validates command wiring but does not prove
published-module availability. Consumer and maintainer guidance now covers
bootstrap requirements, credentials, Go compatibility, caches, dependency
preparation, and pin upgrades. Real pins and live integration remain deployment
work. The full offline suite, API boundary check, and documentation whitespace
checks pass.
## Stage 11 — Validate representative adoption and close the sprint
**Covers:** audit-wide acceptance and adoption evidence. **Primary owners:**
existing external-consumer fixtures, consumer guidance, this plan, and the
remaining-work section of `releasekit.md`.
1. Exercise a source-only consumer with one meaningful extra check and a binary
consumer using `buildinfo`, selected targets, and Gitea delivery. Reuse and
extend the fixtures from prior stages. Verify publication through local Git
remotes and delivery through local HTTP fixtures as separate operations.
2. Review available sibling projects named by the product roadmap read-only.
Use PromptKit and Narratio as the source-only and binary representatives.
Record a concise migration assessment: retained product settings/checks,
release code and repeated tests that can be deleted, runtime-version
adaptation, and required policy
or procedure changes. Label projected deletions as estimates. If a sibling
checkout is unavailable, use the audit evidence and label its verification
date. Keep implementation tests self-contained in ReleaseKit.
3. Assess the final user workflow against the audit: standard tests once,
additional checks declared once, one ordinary delivery invocation, one
versioned CI entry point, clear recovery, and shared artifact/build rules.
Address implementation gaps within their existing stage scope before closing
the sprint. Record any new product decision as such.
4. Reconcile GoDoc, CLI/configuration references, consumer guides, maintained
examples, internal inventory, and the product roadmap with implemented
behavior. Keep the audit's original evidence historical. Record completion
here and link to the remaining adoption/deployment work.
5. Run the standard offline suite and API checks on the final implementation.
Run them with the minimum supported Go 1.25 toolchain when available in the
implementation environment; otherwise record that verification limitation
explicitly. Minimum-version verification is evidence about the existing
module requirement, rather than a new permanent release matrix.
6. Leave source publication, real installation verification, credentials,
workflow activation, live service checks, and changes in sibling repositories
for their deployment/adoption tasks. Follow the maintainer release procedure
when a release is separately requested. Keep ReleaseKit's own deliverables
source-only under the current release policy.
**Completion evidence:** A concise final record identifies the passing checks,
representative workflows, projected adoption savings, implemented API/profile
migration, and remaining deployment work. Every F1–F8 finding has an implemented
resolution and appropriately scoped evidence. Review and commit the final
changes with a clean worktree.
**Completed:** The source-only consumer publication fixture runs one meaningful
compatibility check against its committed note and module, then confirms the
annotated tag on a local Git remote. A separate binary consumer fixture builds
`buildinfo` binaries for selected Linux targets, checks native version output,
and delivers both binaries plus `SHA256SUMS` to a local HTTP Gitea fixture.
PromptKit and Narratio were reviewed read-only on 2026-10-06; the product
roadmap records retained settings, runtime and policy/procedure adaptations,
and projected deletion ranges. No sibling repositories were changed.
The final documentation review reconciled GoDoc, CLI/configuration references,
consumer guidance, Woodpecker examples, the internal inventory, and product
roadmap. The pre-release API migration is `Validate` to `AdditionalChecks` and
`DeliveryRequest.Build` to `*BuildSpec`, with `Prebuilt` for retained artifacts;
JSON `checks` remains the ordered additional-check setting. No new product
decision was required. The completed stages address F1–F8; real source
publication, an immutable tool pin, credentials, workflow activation, and live
Gitea/Woodpecker verification remain deployment work.
The full offline suite and API boundary check pass with Go 1.25.0. Go formatting,
documentation whitespace, and changed local-link checks pass.
## Open Questions
No unresolved product choice is required to implement these stages. The
selected approaches and rationale are recorded in the audit's design choices.
Real deployment pins, credentials, service availability, and per-application
migration scheduling are inputs to subsequent deployment/adoption work. They
are separate from the implementation acceptance criteria above.

View File

@@ -1,7 +1,7 @@
# ReleaseKit: shared release process
Status: Initial implementation, policy adoption, and architecture remediation
are complete. Consumer adoption, publication, and live integration work remain.
are complete. Consumer adoption and live CI integration work remain.
This roadmap records the shared release-process opportunity identified in
PromptKit, ConfigKit, Audita, Notarius, Narratio, and Scriptorium on 2026-09-29,
@@ -227,20 +227,23 @@ publication and delivery operations.
## Remaining work
- Prepare and publish the first ReleaseKit source release under the
[maintainer procedure](../release.md), then deliver its hosted note page.
- Use the [v0.1.0 baseline](../releases/v0.1.0.md) for initial consumer integration
under the [maintainer procedure](../release.md).
- Choose the broader consumer integration test plan and migration sequence.
Evaluate API clarity, product-specific checks, and the infrastructure removed
from each consuming repository.
- Replace the maintained example's ReleaseKit version placeholder with a real
immutable revision or published version. Provision delivery credentials and
activate consumer Woodpecker workflows as part of deployment.
- Provision delivery credentials and activate consumer Woodpecker workflows
using the maintained example's `v0.1.0` pin or a later selected immutable
version as part of deployment.
- Verify live Gitea delivery and Woodpecker execution. Existing verification uses
local Git and HTTP fixtures; no live deployment has been verified.
- Keep ReleaseKit executable binary distribution deferred until deliverables
are deliberately selected. Selecting binaries would require delivery
declarations, target checks, automation responsibilities, and corresponding
release policy and procedure updates.
- Evaluate a maintained ReleaseKit CI image or specialized validation/build
settings when a demonstrated consumer need justifies their maintenance cost
under [ADR 0002](../adr/0002-routine-releases.md).
## Reviewed implementations

View File

@@ -1,164 +0,0 @@
# ReleaseKit audit follow-up review
Date: 2026-10-06.
Reviewed source: `55333b0`.
Status: Complete. R1 and R2 are resolved.
## Scope and assessment
Reviewed the changes since `536a579` against the [audit](audit.md), completed
[implementation plan](implementation.md), [architecture policy](../policy/architecture.md),
and [routine-release decision](../adr/0002-routine-releases.md). The worktree
was clean at the start of the review.
The selected architecture is substantially implemented. One Go module exposes
the root orchestration facade and lightweight `buildinfo` runtime facade.
Internal packages own candidate validation, Git publication and recovery,
Go environments, artifact declarations, managed delivery builds, Gitea effects,
and explicit CI preparation. The CLI adapts profiles, credentials, output, and
exit statuses. Standard validation precedes additive product checks; ordinary
delivery uses one facade-owned build-and-deliver operation. The maintained
consumer workflow invokes the shared versioned CI command.
The audit's F1–F8 changes are present, with behavioral tests for their selected
contracts. R1 below identifies a new defect in the shared Go-environment owner;
R2 identifies increased test cost and coupling introduced by additive validation.
The review found no additional public-type ownership or dependency-direction
gap. The deliberate additive-check, baseline-build, managed-delivery, and CI
preparation decisions remain appropriate. The findings call for implementation
repairs within those decisions.
## R1 — Medium: Go discovery treats successful diagnostics as invalid configuration
Status: Resolved.
Category: Correctness and an accidental environment prerequisite.
Introduced by: `0809312`.
**Evidence:** [Go configuration discovery](../../internal/gotool/gotool.go)
routes both stdout and stderr into the same buffer in `discover` (lines
189–205). `New` parses that combined output as JSON (lines 59–81). A successful
`go env -json` invocation with a warning therefore becomes a decoding failure.
This affects candidate validation and nonempty builds through their shared owner.
**Reproduction:** Create a clean `main` repository with a Go 1.25 module, a
passing test, a matching committed note, and a source-only product profile.
Set `GOPATH` to the installed Go toolchain's `GOROOT`. On Go 1.26.8,
`go test -mod=readonly -count=1 ./...` succeeds with a warning on stderr.
`releasekit check --repo DIR v1.2.3` fails before running that suite:
```text
prepare Go toolchain: decode Go host settings: invalid character 'w' looking for beginning of value
```
The warning-producing configuration is discouraged by Go, but the Go command
accepts it. ReleaseKit's selected environment contract preserves effective
operational settings; it establishes no requirement that successful discovery
produce an empty diagnostic stream. The same decoding failure follows from any
successful discovery command that emits stderr alongside valid stdout JSON.
**Required remediation:** Capture configuration stdout and diagnostics
separately. Parse stdout as JSON and retain stderr for command-failure reporting
or ordinary diagnostics. Preserve subprocess error identity, cancellation,
effective operational settings, and the selected validation/build environments.
**Focused verification:** A controlled Go-command fixture returns valid JSON on
stdout, a diagnostic on stderr, and exit 0; discovery succeeds and preserves
the settings. A failing command retains useful stderr and its cause. Existing
ambient/persistent flag, host-target, cache, and architecture-tuning regressions
continue to pass. These checks add no warning-free configuration requirement.
**Resolution (2026-10-07):** Discovery captures stdout and stderr separately,
parses configuration from stdout, and preserves diagnostic output and subprocess
causes on failure. A subprocess fixture proves successful JSON discovery accepts
stderr diagnostics and preserves host/cache settings; another verifies failure
diagnostics and exit-error identity. The success regression failed before the
fix. Go-environment, candidate-validation, and build regression checks pass.
## R2 — Medium: Wrapper regression testing repeats the project suite inside itself
Status: Resolved.
Category: Test maintainability and development cost.
Introduced by: `3e9b5c1`.
**Evidence:** [The wrapper regression](../../cmd/releasekit/release_wrapper_test.go)
clones the complete repository for each exit-status scenario, overlays a
hand-maintained list of production and test files (lines 32–45), and invokes
the source publication wrapper. The success, rejected-push, and unknown-push
scenarios each run the project's default suite inside the parent suite.
An inherited `RELEASEKIT_SKIP_WRAPPER_TEST` flag prevents recursive execution
of this one test, while the other publication, delivery, build, and workflow
tests run again in each clone.
During this review, process inspection confirmed the nested native publisher,
`go test ./...`, and cloned test binaries. The uncached offline suite passed;
the root package took 40.751 seconds and the CLI package took 115.533 seconds
on this host. These timings are observations, not proposed test-duration limits.
The extra executions provide little distinct evidence about wrapper exit-code
preservation. The file overlay also couples the fixture to unrelated package
changes and supplies only selected uncommitted files, so development checks can
exercise a mixture of the current worktree and committed source.
**Required remediation:** Keep the real source-bootstrap wrapper and local Git
exit-status scenarios, while giving their candidate validation a small,
self-contained test fixture. Assemble the tool source consistently from the
version being tested. Replace the manually maintained production/test overlay
and suite-recursion skip mechanism with a fixture that exercises wrapper
behavior without rerunning ReleaseKit's complete test suite. Retain the actual
publication and recovery behavior already protected by this regression.
**Focused verification:** The real wrapper still preserves success 0, known
failure 1, invalid input 2, and uncertain publication 3. The candidate fixture
runs its standard suite, and captured-endpoint recovery still finds the
intended object with separate fetch and push repositories. The outer default
suite supplies the project's broader behavioral evidence once. Use test scope
and command observations for verification rather than a wall-clock gate.
**Resolution (2026-10-07):** Wrapper fixtures capture the current nonignored
source, including tracked and untracked worktree changes, through one inventory.
They exclude the project's test files and add one small candidate test with an
external validation log. The manually maintained overlay and recursion skip
flag are removed. The real source-bootstrap wrapper preserves statuses 0, 1,
2, and 3; the validation log confirms one suite execution for each valid
candidate and none for invalid input. Captured-endpoint recovery and URL-rewrite
guards still pass with separate fetch and push repositories.
The focused wrapper regression passes in 7.964 seconds on this host. The final
uncached offline suite passes, with the CLI package taking 22.842 seconds.
These measurements record the observed reduction in duplicated work and add
no duration requirement.
## Completion verification
Both fixes are implemented with focused regression evidence. The complete
offline suite and compiled API/dependency checker pass with Go 1.26.8 on
Linux/amd64 using the commands below. Documentation link and whitespace checks
pass. Each remediation unit is committed separately with a plain English
message. Production changes are confined to Go configuration discovery; the
wrapper change preserves the existing publication and recovery contracts.
## Validation and remaining scope
The following checks passed on the reviewed source and after remediation with
Go 1.26.8 on Linux/amd64:
```sh
GOWORK=off GOPROXY=off GONOPROXY=none GOSUMDB=off GOTOOLCHAIN=local \
go test -mod=readonly -count=1 ./...
GOWORK=off GOPROXY=off GOTOOLCHAIN=local go run ./internal/apicheck
```
The R1 reproduction used a temporary committed consumer repository and a native
CLI built from the reviewed source. Publication and delivery suite checks used
local Git and HTTP fixtures. No consuming repository was changed, release was
published, deployment was activated, or live hosted delivery was performed.
This review did not rerun minimum-Go-1.25 validation; the completed implementation
plan records that earlier verification. Real installation, consumer migration,
credentials, and live CI/Gitea verification remain adoption/deployment work in
the [product roadmap](releasekit.md).
R1's implicit warning-free discovery prerequisite is the additional restriction
identified by this review. The review found no further strengthened guarantee
requiring remediation. Preserve existing published-content immutability and the
ordinary source-eligibility observations; the findings require no reproducible
build promise, stronger concurrency guarantee, or additional release gate.

View File

@@ -1,7 +1,7 @@
matrix:
include:
- GO_IMAGE: golang:1.25.0-bookworm
RELEASEKIT_VERSION: REPLACE_WITH_IMMUTABLE_VERSION
RELEASEKIT_VERSION: v0.1.0
when:
- event: tag