1025 lines
58 KiB
Markdown
1025 lines
58 KiB
Markdown
# ReleaseKit staged implementation plan
|
||
|
||
Status: Proposed. All stages are pending; this document introduces no implemented
|
||
features or published contracts.
|
||
|
||
Date: 2026-10-05
|
||
|
||
## Purpose and baseline
|
||
|
||
This plan gives a Luna coding agent bounded implementation assignments, in
|
||
execution order, for the target state in the [feature roadmap](releasekit.md).
|
||
The roadmap owns product intent and selected release conventions. This document
|
||
owns implementation steps, dependencies, acceptance evidence, and progress.
|
||
|
||
The baseline is ReleaseKit commit `43c20b0`. It contains documentation, adopted
|
||
policies, licensing notices, and [ADR 0001](../adr/0001-public-facade.md). It has
|
||
no Go module, packages, executable, tests, or publication automation. The
|
||
worktree was clean when this plan was prepared. The available tools were Go
|
||
1.26.8 on linux/amd64 and Git 2.53.0; these observations are not minimum support
|
||
requirements.
|
||
|
||
The six sibling checkouts are consumer evidence and future migration targets.
|
||
They are independent repositories. Their source and instructions must be
|
||
rechecked before each migration; the earlier line counts are historical review
|
||
measurements. Consult their code through the knowledge graph, indexing a
|
||
repository when necessary. Documents, scripts, and CI configuration may be read
|
||
directly under the discovery instructions.
|
||
|
||
## Execution instructions
|
||
|
||
- Implement stages in integer order. Each stage is one assignment; finish its
|
||
acceptance checks and local commit before starting the next stage. Record
|
||
completed work and evidence here. Read the stage's dependencies and relevant
|
||
decisions before editing.
|
||
- Start with the [developer guide](../development.md) and applicable policies.
|
||
Architecture, testing, documentation, and release policies apply to the core
|
||
implementation. Read the OSS policy when incorporating third-party material.
|
||
- Follow the [architecture policy](../policy/architecture.md) and ADR 0001.
|
||
Add exported declarations as their behavior is implemented, with GoDoc.
|
||
Implement the selected contract with proportionate internal collaborators.
|
||
- The design choices below specify this draft's recommended implementation.
|
||
They become implementation instructions when the plan is approved. Later
|
||
agent-authored code or tests provide evidence of implementation, rather than
|
||
independent authority to strengthen the contract.
|
||
- For each stage, run focused behavioral checks for its changed risks and the
|
||
established offline default suite. Reuse unchanged evidence where appropriate.
|
||
Stage acceptance checks are development checks; they add no publication gates
|
||
beyond the release policy and a repository's selected candidate checks.
|
||
- Use temporary repositories, local bare remotes, test programs, and local HTTP
|
||
servers. Keep fixtures independent of the six consumer checkouts and real
|
||
services. Temporary fixture module replacements may connect test programs to
|
||
this checkout; keep them outside committed production module configuration.
|
||
- Update canonical documentation with each implemented responsibility. Create
|
||
consumer, CLI, configuration, integration, and internal documents when they
|
||
have substantive content. Keep future behavior and stage progress here.
|
||
- Consumer migration stages change the named sibling repository as well as any
|
||
corresponding ReleaseKit examples. Follow that repository's policies, preserve
|
||
unrelated work, and commit each repository separately. When adding a runtime
|
||
dependency, update its module metadata and OSS attribution/companion license
|
||
texts in the same change using the actual selected source pin. A migration
|
||
needs a reachable immutable ReleaseKit pin, as described under Open Questions.
|
||
- Local implementation commits and tests against temporary remotes complete
|
||
stages. Real release publication, remote pushes, CI activation, and credential
|
||
provisioning require the maintainer's corresponding authorization. Do not
|
||
equate prepared integration with verified live delivery.
|
||
|
||
## Implementation decisions
|
||
|
||
### Module, runtime access, and public ownership
|
||
|
||
Use one module, `gitea.maximumdirect.net/eric/ReleaseKit`, preserving the case
|
||
advertised by the forge's Go import metadata. Set the initial Go language
|
||
baseline to `go 1.25.0`, matching the oldest consumer module line. Use APIs
|
||
available on that baseline. Actual execution uses a prepared local toolchain
|
||
capable of building the consumer; Narratio already needs Go 1.26. There is no
|
||
mandatory multi-toolchain release matrix.
|
||
|
||
The supported packages are the root `releasekit` facade and `buildinfo`. Put
|
||
the executable at `cmd/releasekit`. Start with standard-library implementations
|
||
and the installed Git and Go executables. Introduce internal packages as their
|
||
responsibilities land: runtime information, process execution, release engine,
|
||
Git operations, builds, Gitea transport, and CLI adaptation. Put command-owned
|
||
parsing and file-format helpers under `cmd/releasekit/internal/cli`; keep facade
|
||
calls in the `cmd/releasekit` controller. Those helpers return their own settings
|
||
for explicit conversion by the controller and import neither public facade.
|
||
The executable therefore consumes the supported APIs while library internal
|
||
packages retain inward dependencies. There are no public transport clients or
|
||
assembly APIs.
|
||
|
||
The initial runtime API is `buildinfo.Version() string`. It returns an injected
|
||
release identifier when supplied; otherwise it uses the running executable's
|
||
main-module version when present and different from `(devel)`, then `dev` when
|
||
that metadata is unavailable. This supports source installs as well as explicit
|
||
release builds. It describes the application version, not the ReleaseKit
|
||
dependency version. [Go build information](https://pkg.go.dev/runtime/debug#ReadBuildInfo)
|
||
documents the main-module metadata available to implement this fallback.
|
||
|
||
Keep the injected string private in the internal runtime implementation. Keep
|
||
the linker symbol identifier in a small internal contract used by the builder.
|
||
The builder and runtime implementation change together. Consumers call the
|
||
accessor; their configuration supplies no linker symbol. The runtime import
|
||
graph uses the standard library and small runtime implementation, independent
|
||
of orchestration. A tool/runtime version mismatch must be exposed by the native
|
||
version smoke check; do not introduce an exact dependency-version equality gate.
|
||
|
||
### Orchestration API
|
||
|
||
Implement these root operations as the corresponding stages land:
|
||
|
||
| Operation | Request and result responsibilities |
|
||
| --- | --- |
|
||
| `Check(ctx, ReleaseRequest)` | Capture and validate a local committed candidate; return its commit and version. This diagnostic operation does not query publication services, create a tag, or claim remote readiness. |
|
||
| `Publish(ctx, ReleaseRequest)` | Validate once, check authoritative state, create and publish the selected annotated tag, and return publication state and retained recovery facts. |
|
||
| `Build(ctx, BuildRequest)` | Build the selected targets with the requested version, verify a native version invocation, and return source identity and generated artifacts. |
|
||
| `Deliver(ctx, DeliveryRequest)` | Verify tagged source and supplied artifact identity, create or find a hosted release, compare content, and add missing assets with explicit partial or uncertain outcomes. |
|
||
|
||
Each operation returns a facade-owned result and an error. Requests carry the
|
||
repository directory explicitly. `ReleaseRequest` also carries the display
|
||
product name, version, selected remote, optional validation callback, optional
|
||
build specification, and optional output writer. The remote defaults to
|
||
`origin`; publication uses `main`. The callback receives a facade-owned
|
||
`Candidate` containing directory, captured commit, and selected version. A nil
|
||
callback selects the default Go test invocation. A supplied callback replaces
|
||
that invocation with the repository's complete selected validation; it is
|
||
called once. The CLI adapts configured commands into this callback.
|
||
|
||
A build specification carries main package, binary name, and targets. Each
|
||
facade-owned `Target` contains Go OS and architecture strings. A build request
|
||
adds version and output directory. A delivery request identifies version,
|
||
product, repository directory, Gitea destination, and optional build result.
|
||
The Gitea destination carries base URL, owner, repository name, and caller-supplied
|
||
token. Library code obtains no credentials from ambient configuration. Before
|
||
the first remote write, an inspection failure reports that this invocation has
|
||
not attempted mutation. Reserve uncertain-mutation classification and exit 3
|
||
for writes whose authoritative outcome remains unresolved.
|
||
|
||
Publication results identify version, candidate commit, captured endpoint,
|
||
phase, and tag object when created. Use distinct states for `not_attempted`,
|
||
`not_published`, `published`, `conflict`, and `unknown`. These describe this
|
||
invocation; a pre-existing remote release is not described as unpublished.
|
||
Delivery results identify release URL and the matching, uploaded, pending, and
|
||
uncertain assets, with `not_attempted`, `complete`, `partial`, `conflict`, or
|
||
`unknown` state. Ordinary errors preserve useful causes through wrapping.
|
||
Document exactly when nonzero results accompany errors. Add only the named
|
||
types needed to represent these responsibilities; field spelling and internal
|
||
package layout can follow idiomatic Go without changing the decisions here.
|
||
|
||
### CLI and configuration
|
||
|
||
Use standard-library flag parsing and JSON configuration. The default profile
|
||
is `<repository>/releasekit.json`; `--config` selects another file. Configuration
|
||
paths are resolved from the selected repository, whose default is the current
|
||
directory. A profile supplies product identity, remote, candidate commands,
|
||
optional build specification, and optional Gitea delivery declaration. The
|
||
command supplies the version rather than persisting it in the profile.
|
||
|
||
Use this eventual profile shape; add each optional responsibility only when its
|
||
stage implements it:
|
||
|
||
```json
|
||
{
|
||
"product": "Scriptorium",
|
||
"remote": "origin",
|
||
"checks": [{"args": ["sh", "scripts/check-release-candidate.sh"]}],
|
||
"build": {
|
||
"main_package": "./cmd/scriptorium",
|
||
"binary_name": "scriptorium",
|
||
"targets": ["linux/amd64", "linux/arm64"]
|
||
},
|
||
"delivery": {
|
||
"base_url": "https://gitea.maximumdirect.net",
|
||
"owner": "eric",
|
||
"repository": "scriptorium",
|
||
"token_env": "GITEA_RELEASE_TOKEN"
|
||
}
|
||
}
|
||
```
|
||
|
||
This is a planned example, not an existing file or working invocation. Command
|
||
entries also accept an `env` map. Run argument vectors directly, without
|
||
implicit shell parsing. A repository that needs shell syntax selects `sh` or
|
||
`bash` explicitly. Run commands in the captured repository directory and supply
|
||
`RELEASEKIT_VERSION` and `RELEASEKIT_CANDIDATE` for candidate-specific checks.
|
||
Those captured values take precedence over conflicting command environment
|
||
entries. Inherit the remaining environment and overlay explicitly owned values
|
||
without mutating the caller process.
|
||
|
||
An absent or empty check list selects `go test -count=1 ./...`; a nonempty list
|
||
is the repository's complete validation sequence. Decode profile fields
|
||
strictly so unsupported build or delivery settings cannot silently disappear
|
||
from the selected checks. Validate required values for the operation being run;
|
||
a source-only profile needs neither a main package nor credentials.
|
||
The CLI loads the token named by `delivery.token_env`, defaulting to
|
||
`RELEASEKIT_GITEA_TOKEN`, only for delivery. Build receipt identity covers resolved
|
||
build inputs; delivery credentials, destination, and unrelated check settings
|
||
are excluded from that identity.
|
||
|
||
The eventual command forms are:
|
||
|
||
```text
|
||
releasekit version
|
||
releasekit check [--repo DIR] [--config FILE] VERSION
|
||
releasekit publish [--repo DIR] [--config FILE] VERSION
|
||
releasekit build [--repo DIR] [--config FILE] [--output DIR] VERSION
|
||
releasekit deliver [--repo DIR] [--config FILE] [--assets DIR] VERSION
|
||
```
|
||
|
||
Flags precede the positional version. `version` prints `releasekit <version>`.
|
||
Use exit 0 for completed success, 1 for a known failure or conflict, 2 for usage
|
||
or invalid configuration, and 3 for an uncertain remote mutation. Library
|
||
outcomes retain more detail. Send validation progress and diagnostics to stderr;
|
||
stdout presents the command's final result. Signals cancel the operation through
|
||
its context. There is no interactive confirmation loop.
|
||
|
||
### Candidate checks and Git publication
|
||
|
||
Parse stable versions using the roadmap's exact syntax. Validate decimal
|
||
components as strings without introducing a machine-integer size limit. Read
|
||
the release note from the captured commit at `docs/releases/<version>.md`. Its
|
||
first line must be a Markdown H1 containing the configured product name and
|
||
exact version as complete title elements. Preserve the note content for the annotated tag.
|
||
The shared tool imposes no additional note section inventory.
|
||
|
||
`Check` checks a clean worktree and index on `main`, captures HEAD, checks the
|
||
committed note and unused local version, runs validation and selected builds,
|
||
and rechecks local mutable state. `Publish` adds authoritative endpoint and
|
||
remote branch/tag checks before validation and immediately before publication.
|
||
Cleanliness includes untracked files; ordinary Git ignore rules still apply.
|
||
Snapshot resolved request values and CLI profile content for the invocation so
|
||
configuration is not reloaded into different checks midway through the run.
|
||
Source changes remain subject to the ordinary candidate rechecks. The Go API
|
||
accepts caller-supplied values without requiring a particular profile file.
|
||
|
||
Resolve the selected remote's effective push destination using Git's own remote
|
||
configuration semantics. A missing destination or more than one distinct
|
||
effective publication destination is an actionable configuration error because
|
||
this operation needs one authoritative endpoint. A separate fetch URL is
|
||
supported. Inspect the publication endpoint,
|
||
rather than assuming the selected remote's normal fetch URL is authoritative.
|
||
|
||
Use a transient, command-scoped named remote with explicit read and push URLs
|
||
and mirror mode disabled. Verify that both effective URLs equal the captured
|
||
publication destination after Git URL rewriting. Reuse that scoped remote for
|
||
queries and push; persist no new remote configuration. Retain normal Git
|
||
credential and transport settings, carrying remote-specific transport settings
|
||
into the scoped remote as needed. If rewriting prevents establishing this
|
||
equality, report the unresolved destination before mutation.
|
||
Recheck the original remote resolution before pushing. Test ordinary
|
||
`insteadOf`, `pushInsteadOf`, and explicit push-URL cases using local remotes.
|
||
[Git's remote documentation](https://git-scm.com/docs/git-remote) describes the
|
||
effective URL lookup on which this relies.
|
||
|
||
Use exact ref names in remote queries. Require authoritative `main` to equal
|
||
the captured candidate and the selected tag to be absent. Create the annotated
|
||
tag from the committed note with signing disabled for this invocation, inspect
|
||
its object type and peeled commit, then freeze its object ID. Push
|
||
`<tag-object-id>:refs/tags/<version>` with automatic following of tags and mirror
|
||
defaults disabled. Publish no branch updates, unrelated tags, or force updates.
|
||
|
||
A successful push returns immediately as published. After a failed or ambiguous
|
||
push, make one authoritative tag query: an exact object match confirms success;
|
||
absence confirms not published at observation; a different object is conflict;
|
||
an unavailable or uninterpretable answer is unknown. Retain the local tag in
|
||
all failed or uncertain cases. Caller cancellation after push starts also needs
|
||
this bounded reconciliation attempt using a separate finite recovery context.
|
||
Use a 30-second recovery deadline as an operational default, not a guarantee
|
||
that the endpoint will respond. Cancellation before push does not initiate it.
|
||
|
||
The last remote branch check is an observation before the tag push. This design
|
||
provides no transaction locking remote `main` against concurrent writers. Do not
|
||
add branch pushes or assert stronger concurrency guarantees in tests.
|
||
|
||
### Go execution, builds, and assets
|
||
|
||
For ReleaseKit-owned candidate Go commands and builds, use prepared dependencies
|
||
and a local toolchain. Set child environment values `GOWORK=off`, `GOPROXY=off`,
|
||
`GONOPROXY=none`, `GOSUMDB=off`, and `GOTOOLCHAIN=local`. Set module mode to
|
||
readonly, preserving a repository's deliberately selected testing flags.
|
||
ReleaseKit-owned builds replace ambient `GOFLAGS` with `-mod=readonly` and use
|
||
their explicit build arguments; custom validation commands retain their
|
||
deliberately configured flags.
|
||
Preparation of caches and tools occurs separately. These settings do not
|
||
sandbox arbitrary repository callbacks or establish a general network firewall.
|
||
|
||
Build with `CGO_ENABLED=0`, `-mod=readonly`, `-trimpath`, `-buildvcs=false`, and
|
||
linker flags `-s -w` plus the shared version injection. This selects the pure-Go
|
||
build convention already used by the current asset builders. Additional cgo
|
||
toolchains remain outside this implementation. The injected string must use a
|
||
linker-supported initializer. [Go's linker documentation](https://pkg.go.dev/cmd/link)
|
||
defines the `-X` mechanism.
|
||
|
||
Initially verify linux/amd64, linux/arm64, and darwin/arm64. Represent targets
|
||
as values rather than a closed enum; other explicit Go OS/architecture pairs
|
||
can be passed to the prepared compiler and may fail according to its support.
|
||
This establishes no native-execution promise for other platforms.
|
||
|
||
Asset names are `<binary-name>-<version>-<goos>-<goarch>`, with `.exe` when the
|
||
requested Go OS needs it. Binary names and target components must be nonempty
|
||
filename components without path separators, backslashes, CR, or LF, so names
|
||
stay in the output directory and have unambiguous manifest entries. Normalize
|
||
repeated target pairs to one target, retaining their first position. Distinguish
|
||
the display product name used by notes from this binary name. Preserve selected
|
||
target order for progress; generate manifests in filename order.
|
||
|
||
For nonempty targets, invoke the built application with `version` and require
|
||
`<binary-name> <version>` plus a final newline. Reuse a target artifact when it
|
||
matches `GOHOSTOS/GOHOSTARCH`; otherwise build a temporary native executable
|
||
with the same flags and injection. Determine the host independently of ambient
|
||
`GOOS/GOARCH`. Native smoke binaries are temporary and are not extra assets.
|
||
An empty target set performs no Go build or version invocation. Source-only
|
||
projects may retain an explicitly selected application check; no binary check
|
||
is silently imposed on them.
|
||
|
||
Candidate build checks use a temporary output directory outside the worktree
|
||
and discard it. Artifact builds record the commit, version, main package,
|
||
targets, compiler identity, and generated filename/hash pairs. Return these
|
||
facts in `BuildResult`. The CLI persists them in an internal local receipt,
|
||
`.releasekit-build.json`, alongside the generated files after a successful
|
||
complete build and smoke check. A partial build returns progress without a
|
||
receipt authorizing delivery. This receipt is for tool coordination, with no
|
||
public format or attestation promise. It contains no credentials and is not a
|
||
hosted asset. Build output defaults to `dist`; create
|
||
the directory as needed, regenerate owned local filenames, and preserve
|
||
unrelated files. Report generated files on partial local failure and clean up
|
||
only tool-owned temporary paths.
|
||
|
||
Delivery uses a clean checkout whose HEAD equals the selected local tag's peeled
|
||
commit; detached HEAD is valid. Read the note from that commit and snapshot the
|
||
selected settings. Repository-local tracked profiles come from that source;
|
||
explicit caller-supplied settings are identified in the build result. Verify
|
||
the hosted repository already has the same tag targeting that commit before
|
||
creating a release. Existing lightweight historical tags may be inspected and
|
||
delivered; new publication follows the annotated-tag standard. Do not require
|
||
current remote `main` to remain at an old release commit during delivery retries.
|
||
|
||
The CLI's `deliver --assets DIR` consumes a verified build receipt and checks
|
||
file hashes, selected filenames, and source/build-input identity before remote
|
||
mutation. When no directory is supplied, build into a temporary directory from
|
||
the tagged checkout and then deliver. With zero targets, optional hosted delivery
|
||
creates a note page without a binary manifest. Neither mode reruns the candidate
|
||
test suite or changes source-publication status.
|
||
|
||
### Hosted delivery and Woodpecker
|
||
|
||
Use a small internal standard-library Gitea REST client. On 2026-10-05 the host's
|
||
[version endpoint](https://gitea.maximumdirect.net/api/v1/version) reported Gitea
|
||
1.25.4; its [served API schema](https://gitea.maximumdirect.net/swagger.v1.json)
|
||
confirmed release-by-tag lookup, JSON release creation, asset listing, and
|
||
multipart attachment upload. Consult the host's schema during implementation;
|
||
record used operations in the integration guide. This observation is not an
|
||
all-version Gitea compatibility promise.
|
||
|
||
Read the tag through `/api/v1/repos/{owner}/{repo}/tags/{tag}` and verify its
|
||
`commit.sha`. Use the repository API prefix for each following operation. Find
|
||
the release through `/releases/tags/{tag}`. Create it through
|
||
`POST /releases` with the existing tag, captured commit, title from the note's
|
||
H1, complete committed note as body, and stable, non-draft settings. A found
|
||
release must match the note body and tag and be stable/non-draft; retain its
|
||
existing title, including a historical title chosen by other tooling. A content
|
||
conflict is reported; its body, title, assets, and tag are not edited. Existing
|
||
historical pages remain intact.
|
||
|
||
List attachments through `/releases/{id}/assets`. Identify expected filenames
|
||
and stream their downloads to compare SHA-256 content; size and name alone do
|
||
not prove a match. Use multipart field `attachment` and the filename query
|
||
parameter for missing uploads. The client obtains no automatic tag-creation
|
||
responsibility. Keep authorization on the configured service origin when
|
||
following attachment URLs or redirects; never include token values in receipts
|
||
or diagnostics.
|
||
|
||
For nonempty binary sets, generate `SHA256SUMS` with lowercase hashes, two spaces,
|
||
filenames, and LF-terminated lines, sorted by filename. It describes the complete
|
||
declared binary set and excludes itself and the private receipt. An existing
|
||
manifest must match that expected content. Fill missing assets covered by that
|
||
manifest only with matching bytes. A manifest describing a different or smaller
|
||
set cannot be replaced to extend that version. Leave unrelated attachments
|
||
untouched.
|
||
|
||
Inspect all known declared asset and manifest conflicts before uploading.
|
||
Upload missing binaries in filename order, then a missing manifest. HTTP writes
|
||
are separate operations. After an ambiguous creation or upload, re-read the
|
||
affected resource once; classify matching content as completed, conflict as
|
||
conflict, and inaccessible or still-indeterminate content as unknown. Handle
|
||
concurrent creation by finding and verifying the created resource. Do not
|
||
blindly retry writes or delete attachments. Record partial progress so an
|
||
operator can rerun against the same tag and retained assets.
|
||
|
||
Woodpecker uses tag-triggered repository-local YAML with a pinned Go/tool image
|
||
and a pinned ReleaseKit source install. Provide an example using an official Go
|
||
image plus a separate provisioning step that installs ReleaseKit from its
|
||
immutable release pin and prepares consumer module caches. Build and deliver
|
||
then run with offline Go execution. This honors ReleaseKit's source-only initial
|
||
distribution; a dedicated ReleaseKit container image would require a separate
|
||
deliverable decision. Use the repository's selected Go toolchain image, which
|
||
must satisfy its own module requirements.
|
||
|
||
Use `CI_COMMIT_TAG` and `CI_COMMIT_SHA` to bind the workflow to tagged source,
|
||
with an explicit tag fetch when the checkout omits local tag refs. The build step
|
||
writes to ignored `dist`; the delivery step shares the workspace and supplies
|
||
the Gitea token from a Woodpecker secret. Pin actual image digests and source
|
||
versions when adopting the example. Pipeline preparation may access dependency
|
||
services; candidate validation and builds use the prepared caches. CI does not
|
||
call `publish`, push refs, or gate source completion. The supported retry is a
|
||
rerun from the same tagged source with content comparison; reproducible bytes
|
||
across arbitrary toolchains or elapsed time are not promised.
|
||
|
||
## Stage 1: Establish the Go module and development baseline
|
||
|
||
Status: Pending. Depends on the baseline only.
|
||
|
||
1. Add the module with the selected path and language baseline. Add root package
|
||
documentation for the orchestration facade and establish ordinary Go layout.
|
||
2. Keep committed module state independent of sibling checkouts and workspaces.
|
||
Start without external runtime dependencies or a generic plugin framework.
|
||
3. Add the working offline developer test command and initial implemented-package
|
||
inventory. Update README to its actual implemented boundary.
|
||
|
||
Acceptance: module loading and `go test ./...` work with the prepared local
|
||
toolchain and network disabled. Review module identity and licensing notices.
|
||
Do not invent tests merely to assert that an empty package exists.
|
||
|
||
## Stage 2: Implement the runtime version facade
|
||
|
||
Status: Pending. Depends on Stage 1.
|
||
|
||
1. Implement `buildinfo.Version` and its internal injected-string and main-module
|
||
fallback logic. Keep runtime state private and the public accessor small.
|
||
2. Add the internal injection-symbol contract without importing orchestration
|
||
into the runtime path. Test injected precedence and missing/development
|
||
metadata through stable internal seams and a small executable fixture.
|
||
3. Add `cmd/releasekit` with a working `version` command using this accessor.
|
||
Record its implemented command contract and the runtime consumer guidance.
|
||
|
||
Acceptance: a source-built fixture reports `dev`; a fixture linked with a stable
|
||
version reports that version. Fallback metadata uses the executable main module.
|
||
CLI version output is correct and no runtime orchestration initialization occurs.
|
||
|
||
## Stage 3: Protect public contracts and dependency direction
|
||
|
||
Status: Pending. Depends on Stage 2.
|
||
|
||
1. Add a compiled-export boundary checker for both facades using `go list` export
|
||
data and `go/types`. Inspect exported signatures, fields, callbacks, aliases,
|
||
generic constraints, and pointer/value method sets recursively.
|
||
2. Assert facade ownership of public named types. Permit deliberately selected
|
||
standard-library contracts. Protect the private-state forwarding approach
|
||
against leaked internal types and promoted implementation methods.
|
||
3. Add import-direction checks: internal production packages use internal
|
||
contracts; the runtime facade's dependency closure excludes orchestration,
|
||
process, build, Gitea, and CLI implementation.
|
||
4. Use small negative fixtures proving that the checker catches a leaked type
|
||
and promoted internal method, and accepts a private implementation field.
|
||
|
||
Acceptance: actual exports pass and meaningful negative fixtures fail. Tests
|
||
inspect contracts and imports, with no fixed inventory of future internal
|
||
package names. Extend these checks as subsequent exports land.
|
||
|
||
## Stage 4: Implement profile loading and command adaptation
|
||
|
||
Status: Pending. Depends on Stage 3.
|
||
|
||
1. Implement JSON product, remote, and command settings under an internal CLI
|
||
adapter. Add strict field decoding, directory resolution, required-value
|
||
diagnostics, direct argument execution, and per-child environment overlays.
|
||
2. Implement an internal cancellable process runner with directory, argument,
|
||
environment, stdout, stderr, and exit-error support. Use `os/exec` directly;
|
||
expose no public runner abstraction solely for test assembly.
|
||
3. Add CLI parsing infrastructure and selected usage/exit behavior. Advertise
|
||
commands only when their following stages implement them.
|
||
4. Add small profile examples and `docs/config.md` for implemented fields.
|
||
|
||
Acceptance: paths and arguments containing spaces remain separate arguments;
|
||
selected environment values reach the child without changing process globals;
|
||
missing executables, invalid configuration, and cancellation report useful
|
||
errors. Tests use controlled local child commands and temporary directories.
|
||
|
||
## Stage 5: Capture and validate one local candidate
|
||
|
||
Status: Pending. Depends on Stage 4.
|
||
|
||
1. Implement stable-version syntax, clean `main` and index/worktree inspection,
|
||
captured HEAD, profile snapshot/note loading, title identity, and unused local
|
||
tag checks. Preserve immutable candidate facts in internal values.
|
||
2. Implement default offline Go validation and callback adaptation. Bind the
|
||
callback to the captured candidate; pass captured version/commit to CLI
|
||
commands. Call the complete validation callback once, stopping on failure.
|
||
3. Recheck branch, HEAD, and cleanliness after validation. Retain the captured
|
||
settings throughout the operation. Implement the public `Check` operation
|
||
and local diagnostic `check` command.
|
||
4. Document that local check success provides local candidate evidence and makes
|
||
no authoritative remote availability claim.
|
||
|
||
Acceptance: temporary repositories cover invalid versions, missing or mismatched
|
||
committed notes, dirty tracked/untracked state, existing local tags, detached
|
||
HEAD, callback failure, and a callback changing HEAD or the worktree. Count a
|
||
successful callback once. No test needs a publication service, and `Check`
|
||
creates no tag or remote ref.
|
||
|
||
## Stage 6: Resolve and inspect the authoritative endpoint
|
||
|
||
Status: Pending. Depends on Stage 5.
|
||
|
||
1. Implement effective push-URL capture, command-scoped remote configuration,
|
||
matching read/write resolution, and endpoint rechecks described above.
|
||
2. Implement exact remote main/tag queries with distinct present, absent,
|
||
conflicting, and unreadable results. Query failures never establish absence.
|
||
3. Compose the pre-validation and pre-publication remote guards around captured
|
||
local state. Require main equality, rather than ancestor-only publication.
|
||
|
||
Acceptance: local remotes cover a separate fetch endpoint, explicit push URL,
|
||
ordinary URL rewrites, multiple push destinations, missing main, conflicting
|
||
tags, main ahead/behind the candidate, endpoint changes, and remote failure.
|
||
Queries leave local tags, persistent remote configuration, and remote refs intact.
|
||
|
||
## Stage 7: Create and push the exact annotated tag
|
||
|
||
Status: Pending. Depends on Stage 6.
|
||
|
||
1. Implement public publication request/result values and explicit conversion
|
||
into the engine. Validate once between the complete preflight guards.
|
||
2. Create an annotated tag from captured note bytes, inspect type and peeled
|
||
commit, capture its object ID, and push only that object to the selected ref.
|
||
3. Recheck mutable local state and endpoint before the push, including the local
|
||
tag still identifying the captured object. A changed local tag prevents this
|
||
invocation from proceeding; cleanup remains deliberate recovery.
|
||
4. On successful push, return published state without another remote read-back.
|
||
On push error, retain the tag and return unknown until Stage 8 adds resolution.
|
||
|
||
Acceptance: a local bare remote receives the expected tag object and commit;
|
||
its main and unrelated refs do not change. Follow-tags and mirror configuration
|
||
cannot expand publication. Note content, tag identity, and one-validation
|
||
behavior are checked through the public facade. Restrict stage trials to test
|
||
remotes while failure handling is incomplete.
|
||
|
||
## Stage 8: Resolve rejected and ambiguous publication
|
||
|
||
Status: Pending. Depends on Stage 7.
|
||
|
||
1. Add the one-query reconciliation path and public error/result classification.
|
||
Preserve the original push cause when resolution does not confirm success.
|
||
2. Give post-push cancellation a separate bounded recovery context. Retain local
|
||
tag/object facts when the read fails or recovery is cancelled/times out.
|
||
3. Add real rejected-push tests using bare-remote hooks. Simulate lost
|
||
acknowledgments at the subprocess boundary after a real successful push.
|
||
Separate known absence, conflicting object, and unavailable-query cases.
|
||
4. Cover a remote branch change during validation and local tag mutation before
|
||
push. Keep concurrency promises at the observed guard boundaries.
|
||
|
||
Acceptance: exact remote object match succeeds despite a reported push error;
|
||
missing, conflicting, and unavailable remote tags have distinct outcomes. Failed
|
||
pushes issue one reconciliation query, successful pushes issue none, and no
|
||
recovery force-update or automatic tag deletion occurs.
|
||
|
||
## Stage 9: Expose publication and document ReleaseKit bootstrap
|
||
|
||
Status: Pending. Depends on Stage 8.
|
||
|
||
1. Wire the complete public publisher into `releasekit publish`, with selected
|
||
progress output, final result, exit classification, and signal cancellation.
|
||
2. Add ReleaseKit's source-only profile and one short maintainer entry script.
|
||
The profile selects the offline default suite; no inherited race, lint,
|
||
documentation, image, or platform gates are added.
|
||
3. Create `docs/release.md` now that publication works. Name authoritative
|
||
`origin` at the ReleaseKit forge URL and `main`; document preparation,
|
||
successful-push completion, exact-object recovery, local tag retention, and
|
||
deliberate cleanup of proven unpublished tags.
|
||
4. Document first-release execution from the captured candidate source using
|
||
the local Go toolchain, before a released ReleaseKit executable exists.
|
||
Include immutable release-note licensing footer construction and dependency
|
||
preparation separate from validation.
|
||
5. Update current development documentation and the policy-adoption roadmap's
|
||
bootstrap status to the implemented boundary. Preserve pending deliverables.
|
||
|
||
Acceptance: an end-to-end CLI fixture publishes to a local remote through a
|
||
committed profile and returns the expected exit/output behavior. Runbook commands
|
||
are exercised using a temporary repository configured like ReleaseKit. This
|
||
stage prepares self-publication and does not publish a real ReleaseKit release.
|
||
|
||
## Stage 10: Build selected targets with shared version injection
|
||
|
||
Status: Pending. Depends on Stage 9.
|
||
|
||
1. Implement public build values and internal build execution using the fixed
|
||
flags, version symbol, filename convention, and prepared Go environment.
|
||
2. Build explicit OS/architecture pairs and verify the application `version`
|
||
invocation using a host artifact or temporary native build. Preserve
|
||
caller-owned output files and report partial generated output on failure.
|
||
3. Return source identity, artifact paths, filenames, targets, hashes, and
|
||
compiler identity. Keep byte reproducibility and cross-platform execution
|
||
promises outside the result contract.
|
||
4. Add a temporary consumer module importing only `buildinfo` and exposing the
|
||
canonical version command. Its local replacement is fixture-only.
|
||
|
||
Acceptance: the fixture compiles for the three initial targets and a native
|
||
execution reports the injected version. An ambient cross-target environment
|
||
does not select the smoke host. Empty targets perform no build or smoke test;
|
||
missing main packages, build failures, incorrect version output, unsafe binary
|
||
names, and cancellation fail with useful partial results.
|
||
|
||
## Stage 11: Integrate candidate builds and artifact command
|
||
|
||
Status: Pending. Depends on Stage 10.
|
||
|
||
1. Add build profile fields, CLI `build`, and the private artifact receipt.
|
||
Bind receipts to source/build-input identity and generated hashes. Validate
|
||
data on reload; leave the receipt outside the public API and hosted asset list.
|
||
2. Integrate selected builds into `Check` and `Publish` after the single candidate
|
||
callback. Use disposable output outside the worktree for candidate builds.
|
||
Recheck mutable state after the entire validation/build sequence.
|
||
3. Add ignored `dist` output and source-only and binary-producing examples.
|
||
Document the API, profile target selection, version invocation, and build
|
||
output ownership.
|
||
4. Refresh facade and runtime dependency checks with the new values.
|
||
|
||
Acceptance: source-only publication invokes no builder; selected build failure
|
||
prevents tag creation; selected builds inject the exact candidate version;
|
||
callback validation runs once. CLI artifacts and receipts agree on filenames,
|
||
hashes, commit, and resolved build settings. Generated validation output does
|
||
not dirty the candidate. This completes the first source-publication/build
|
||
capability slice.
|
||
|
||
## Stage 12: Pilot publication in PromptKit
|
||
|
||
Status: Pending. Depends on Stage 11 and a reachable immutable tool pin.
|
||
|
||
1. Review PromptKit's current instructions, release policies, and entry scripts.
|
||
Add a source-only profile using its actual note display name, currently
|
||
`Promptkit`. Keep its application-specific consumer example checks and other
|
||
deliberately adopted candidate gates in its validation command.
|
||
2. Replace repeated release guards and tag publication with a short ReleaseKit
|
||
invocation. Move note identity validation to ReleaseKit; remove extra shared
|
||
note-section requirements only through the corresponding local policy change.
|
||
3. Update installation prerequisites, local release wiring tests, and maintainer
|
||
documentation. Retain no duplicate mandatory pre-check before publication.
|
||
|
||
Acceptance: isolated repository fixtures exercise the new wrapper and profile
|
||
against a local remote, preserve source-only behavior, and run the selected
|
||
candidate checker once. PromptKit's own suite passes. Record deleted shared
|
||
mechanics separately from retained product checks. No Go runtime dependency or
|
||
hosted page is introduced for this library.
|
||
|
||
## Stage 13: Pilot publication in Scriptorium
|
||
|
||
Status: Pending. Depends on Stage 12.
|
||
|
||
1. Adapt Scriptorium's publication entry point and release policy to the common
|
||
profile/command. Preserve its selected candidate test flags and genuinely
|
||
product-owned checks in a small local candidate command.
|
||
2. Retain its existing candidate build check temporarily: its application has
|
||
no canonical runtime version command yet. Document that shared builds are
|
||
deferred to Stage 19; the existing delivery pipeline continues meanwhile.
|
||
3. Transfer exact-object publication/failure tests into shared coverage and
|
||
retain a small wrapper/configuration test locally. Update its runbook.
|
||
|
||
Acceptance: local-remote fixtures confirm common publication and bounded
|
||
recovery without changing the existing asynchronous deliverables. Scriptorium's
|
||
own suite passes. The two pilots substantiate the same public facade with
|
||
different product checks and endpoint configurations.
|
||
|
||
## Stage 14: Find and create Gitea release pages
|
||
|
||
Status: Pending. Depends on Stage 13.
|
||
|
||
1. Implement the small internal REST transport using the served API operations,
|
||
explicit destination/token inputs, context cancellation, and structured
|
||
failure mapping. Use standard HTTP and JSON packages.
|
||
2. Verify the hosted tag targets the captured source commit. Find a release by
|
||
tag, create a missing stable release from the committed note, and verify
|
||
existing note body/tag and stable, non-draft state before accepting it.
|
||
Preserve the existing title.
|
||
3. Handle create conflicts and lost acknowledgments by one lookup and content
|
||
comparison. Never edit the existing page to make it match.
|
||
4. Add `docs/integrations/gitea.md` describing implemented API interactions,
|
||
credential supply, source binding, and failure semantics.
|
||
|
||
Acceptance: `httptest.Server` covers found, missing, created, conflicting,
|
||
unauthorized, malformed, cancelled, and ambiguous-create results. A missing or
|
||
wrong hosted tag prevents page creation. Existing historical titles are retained
|
||
when the body, tag, and release state match. Fixture assertions cover actual
|
||
request paths, payloads, and authentication without using real credentials.
|
||
|
||
## Stage 15: Inspect asset and manifest content
|
||
|
||
Status: Pending. Depends on Stage 14.
|
||
|
||
1. Generate the expected binary manifest from the declared build result. Add
|
||
attachment discovery and streaming hash comparison of existing assets.
|
||
2. Compare existing `SHA256SUMS` with the complete declared manifest. Identify
|
||
matching, missing, conflicting, and unverifiable content separately.
|
||
3. Inspect all declared conflicts before any upload and preserve unrelated
|
||
attachments. Keep download authorization confined to the configured origin.
|
||
|
||
Acceptance: equal name/size with different bytes is conflict; matching content
|
||
is accepted; a full matching manifest can cover missing binaries; a subset or
|
||
different manifest is conflict; unreadable content is not treated as missing.
|
||
Source-only delivery generates no binary manifest. No write endpoint is used
|
||
by inspection tests.
|
||
|
||
## Stage 16: Upload missing assets and report partial delivery
|
||
|
||
Status: Pending. Depends on Stage 15.
|
||
|
||
1. Add multipart uploads for missing binaries in filename order, followed by a
|
||
missing manifest. Record completed work and pending asset identities.
|
||
2. Resolve ambiguous uploads by one resource read and content comparison.
|
||
Handle concurrent matching uploads without creating replacement content;
|
||
detect duplicate/conflicting attachment names as conflicts.
|
||
3. Implement rerun behavior that accepts existing matching files, adds missing
|
||
ones, and stops on conflicts. Preserve every existing page and attachment.
|
||
4. Add tests where the first binary succeeds, a later write fails, and a second
|
||
invocation completes only the missing assets; also cover a lost manifest
|
||
acknowledgment and failure of the reconciliation read.
|
||
|
||
Acceptance: partial and unknown outcomes retain exact completed/pending facts;
|
||
retries do not overwrite or delete content; no blind repeat POST is made after
|
||
an ambiguous acknowledgment. Published manifest constraints hold across reruns.
|
||
|
||
## Stage 17: Expose tagged-source delivery through the facade and CLI
|
||
|
||
Status: Pending. Depends on Stage 16.
|
||
|
||
1. Implement `Deliver`, its facade-owned request/result values, and conversions.
|
||
Bind source note, resolved build settings, tag commit, and hosted repository
|
||
as specified.
|
||
2. Add delivery profile fields, environment-name token loading in the CLI, and
|
||
`deliver` with an optional verified assets directory. With no directory,
|
||
build tagged-source artifacts in temporary storage before uploading.
|
||
3. Accept detached tagged checkouts and historical tags without requiring old
|
||
remote main equality. Verify receipt identity/hashes before supplied assets
|
||
are used. Keep the library credential input explicit.
|
||
4. Add current consumer/CLI guidance for source status, delivery status,
|
||
retained assets, and retry commands. Extend public boundary checks.
|
||
|
||
Acceptance: a facade/CLI end-to-end fixture builds tagged source and delivers to
|
||
a local server; a rerun is content-aware. Wrong commit, stale build settings or
|
||
receipt, tampered assets, and missing credentials prevent relevant writes. Candidate
|
||
tests and Git publication are not run by delivery. A delivery failure leaves
|
||
the existing source tag intact and reports only delivery failure.
|
||
|
||
## Stage 18: Provide the common Woodpecker integration
|
||
|
||
Status: Pending. Depends on Stage 17 and the delivery-capable tool pin.
|
||
|
||
1. Add a maintained example tag pipeline using a pinned Go image, explicit
|
||
ReleaseKit source installation and cache preparation, artifact build, and
|
||
delivery with the configured secret. Explain how consumers pin their image
|
||
and tool source; create no new ReleaseKit image-distribution requirement.
|
||
2. Bind tag and commit variables to the checkout, fetch the selected tag when
|
||
necessary, share generated assets between steps, and keep output ignored.
|
||
3. Document preparation versus offline execution, asynchronous status, and
|
||
rerunning the same immutable tag. The workflow executes no publisher.
|
||
4. Exercise its shell command sequence locally against a fixture and local
|
||
server. Verify YAML with an available supported Woodpecker validator when
|
||
available; report that live runner behavior remains unverified otherwise.
|
||
|
||
Acceptance: the maintained commands reach common build/delivery operations with
|
||
the selected version and commit, and secrets enter only the delivery step.
|
||
Static/manual YAML review and local command evidence are recorded accurately.
|
||
CI success is not a source release gate. The
|
||
[Woodpecker environment reference](https://woodpecker-ci.org/docs/usage/environment)
|
||
owns the runner-provided tag and commit variables.
|
||
|
||
## Stage 19: Standardize Scriptorium runtime information and builds
|
||
|
||
Status: Pending. Depends on Stage 18 and a released runtime dependency pin.
|
||
|
||
1. Add the `buildinfo` dependency and canonical `scriptorium version` command
|
||
before configuration/provider initialization. Use graph discovery to locate
|
||
its CLI boundary; the earlier implementation has no release version command.
|
||
2. Set main package `./cmd/scriptorium`, binary name `scriptorium`, and its
|
||
existing Linux amd64/arm64 asset targets in the profile.
|
||
3. Replace the temporary local candidate build loop from Stage 13 with shared
|
||
candidate builds. Retain only product checks and a small version/wiring test.
|
||
4. Update current CLI contracts and compatibility impact documentation.
|
||
|
||
Acceptance: shared builds report the injected version without credentials or
|
||
service access. The unchanged two-asset selection is used for candidate checks.
|
||
Runtime dependency checks show the application needs only `buildinfo` for this
|
||
responsibility; its ordinary suite passes.
|
||
|
||
## Stage 20: Pilot common delivery in Scriptorium
|
||
|
||
Status: Pending. Depends on Stage 19.
|
||
|
||
1. Replace its duplicated Woodpecker build loop and release-plugin step with the
|
||
common example adapted to its pinned Go/tool versions and Gitea destination.
|
||
2. Keep the committed note as the hosted body and maintain the existing two
|
||
Linux assets and checksum deliverable. Add ignored local build output.
|
||
3. Remove its repeated asset builder code once local fixture evidence exercises
|
||
common build and retry delivery. Update its delivery runbook and tests.
|
||
|
||
Acceptance: local fixture execution verifies first delivery, matching rerun,
|
||
partial delivery recovery, and conflicting bytes. The repository's source
|
||
publication path waits for no CI or attachments. Record live activation as a
|
||
separate maintainer action; preserve historical release workflows at old tags.
|
||
|
||
## Stage 21: Migrate ConfigKit publication
|
||
|
||
Status: Pending. Depends on Stage 20.
|
||
|
||
1. Add a source-only profile and wrapper using the common publisher. Its current
|
||
sequential main/tag publication becomes main-first preparation and tag-only
|
||
publication. Update the adopted policy and maintainer runbook together.
|
||
2. Preserve its existing selected baseline-toolchain, test, vet, and build
|
||
checks in its candidate checker where its local policy justifies them.
|
||
These remain ConfigKit checks, not ReleaseKit-wide requirements.
|
||
3. Remove duplicated ref checks, annotated-tag creation, and push recovery.
|
||
Retain a small profile/wrapper test and run its suite.
|
||
|
||
Acceptance: a local fixture refuses publication until authoritative main equals
|
||
the candidate, then publishes only the tag with one candidate-check invocation.
|
||
ConfigKit gains no runtime import, hosted page, or distributed binary.
|
||
|
||
## Stage 22: Migrate Notarius publication
|
||
|
||
Status: Pending. Depends on Stage 21.
|
||
|
||
1. Add a source-only profile and common publication wrapper. Its existing
|
||
branch push and lightweight tag become prepared main plus annotated tag.
|
||
Update the adopted policy and procedure with that deliberate change.
|
||
2. Retain its existing explicit host version check temporarily in its local
|
||
checker. Remove repeated common release guards and shared publication tests.
|
||
3. Preserve a small wrapper/check invocation test and verify ordinary behavior.
|
||
|
||
Acceptance: local remotes demonstrate the new publication approach and bounded
|
||
recovery. Source-only deliverables and the current version-check prerequisite
|
||
remain unchanged until the next stage.
|
||
|
||
## Stage 23: Standardize Notarius runtime version access
|
||
|
||
Status: Pending. Depends on Stage 22 and a released runtime dependency pin.
|
||
|
||
1. Replace its private override/resolution mechanism with `buildinfo`. Preserve
|
||
its existing `--version` invocation and add the canonical `version` command
|
||
for common smoke checks, with `notarius <version>` output.
|
||
2. Document the common metadata/`dev` fallback and its deliberate effect on any
|
||
existing unversioned-build diagnostic behavior. Update owned tests/contracts
|
||
rather than silently preserving obsolete private override assumptions.
|
||
3. Replace the explicit host check's private linker flags with a small local
|
||
invocation of the shared Build API for the host target. This remains an
|
||
explicitly selected local check, not a distributed target declaration.
|
||
The API accepts explicit host Go targets as described above.
|
||
|
||
Acceptance: both version invocations report the same injected value without
|
||
configuration or credentials, and the deliberate source-build behavior is
|
||
covered. The source-only profile still has no automatic binary targets or Gitea
|
||
page; the separately selected host check runs once with its candidate checker.
|
||
|
||
## Stage 24: Migrate Audita publication
|
||
|
||
Status: Pending. Depends on Stage 23.
|
||
|
||
1. Replace atomic main/tag publication with main-first preparation and the
|
||
common annotated-tag publisher. Retain its `--check` user entry by mapping it
|
||
to common local `check`; map `--publish` to common publication.
|
||
2. Preserve current tests and its existing builder temporarily as selected
|
||
candidate checks. Update the local release policy and completion wording.
|
||
3. Transfer shared atomic/lightweight publication tests to the common contract,
|
||
retaining tests of the Audita command mapping and local checks.
|
||
|
||
Acceptance: diagnostic mode performs no remote publication; publication refuses
|
||
an unprepared main and uses an annotated tag. The configured candidate sequence
|
||
runs once and existing asynchronous Linux deliverables remain selected.
|
||
|
||
## Stage 25: Standardize Audita runtime information and builds
|
||
|
||
Status: Pending. Depends on Stage 24 and a released runtime dependency pin.
|
||
|
||
1. Add `audita version` using `buildinfo`, before application configuration and
|
||
provider initialization. The earlier CLI has no release-version accessor.
|
||
2. Declare `./cmd/audita`, binary name `audita`, and linux/amd64 plus linux/arm64.
|
||
Replace `scripts/build-release.sh` mechanics with shared candidate/build
|
||
operations and retain product-owned tests.
|
||
3. Add a small application version-command test and update current contracts.
|
||
|
||
Acceptance: native smoke verifies the injected tag and needs no credentials;
|
||
both existing Linux assets retain their names/target selection. Audita's own
|
||
suite passes and duplicate candidate build work is removed.
|
||
|
||
## Stage 26: Migrate Audita delivery
|
||
|
||
Status: Pending. Depends on Stage 25.
|
||
|
||
1. Adapt the common tag workflow to Audita's pinned image/tool, Gitea repository,
|
||
and secret name. Replace release-plugin skip-by-name behavior with shared
|
||
content verification and additive delivery.
|
||
2. Update delivery/retry documentation and remove unused build wrapper code.
|
||
|
||
Acceptance: local first-run, rerun, conflicting-content, and partial-delivery
|
||
fixtures exercise the actual configured filenames and complete manifest. Source
|
||
completion and live activation remain separate from delivery verification.
|
||
|
||
## Stage 27: Migrate Narratio publication
|
||
|
||
Status: Pending. Depends on Stage 26.
|
||
|
||
1. Retain main-first preparation and replace lightweight tags with common
|
||
annotated publication. Adapt its candidate checker and release entry point,
|
||
keeping its selected product checks and build mechanics temporarily.
|
||
2. Update policy/runbook and retire common version/note/ref helpers where their
|
||
behavior is now shared. Preserve remaining helper uses until Stage 28.
|
||
|
||
Acceptance: local publication fixtures cover exact candidate/tag identity and
|
||
common recovery; the checker runs once. Narratio retains its three declared
|
||
asset targets and existing delivery pipeline until subsequent stages.
|
||
|
||
## Stage 28: Standardize Narratio runtime information and builds
|
||
|
||
Status: Pending. Depends on Stage 27 and a released runtime dependency pin.
|
||
|
||
1. Replace its private buildinfo variable with the facade in its existing
|
||
`narratio version` command. Preserve output shape and update tests to use
|
||
supported behavior rather than mutating a private version variable.
|
||
2. Declare `./cmd/narratio`, binary name `narratio`, and linux/amd64,
|
||
linux/arm64, darwin/arm64. Use the prepared toolchain required by its module.
|
||
3. Replace `build-release-assets.sh` flags, host smoke, and target loop with
|
||
shared builds. Remove duplicate build invocation from its candidate checker.
|
||
Preserve product checks and remove helpers that now have no remaining use.
|
||
|
||
Acceptance: the native version probe and all three cross-builds pass; foreign
|
||
platform compilation is reported without a native-execution claim. A nonempty
|
||
caller output directory can retain unrelated files, and no broad recursive
|
||
cleanup is inherited from the former builder.
|
||
|
||
## Stage 29: Migrate Narratio delivery
|
||
|
||
Status: Pending. Depends on Stage 28.
|
||
|
||
1. Replace its release plugin and repeated tag-pipeline candidate validation
|
||
with the common prepared build/delivery workflow. Candidate validation belongs
|
||
to source publication; tagged delivery does not repeat it as a gate.
|
||
2. Keep its three binary assets, committed note, Gitea destination, and complete
|
||
checksum manifest. Adapt pinned images and tool versions to its Go baseline.
|
||
3. Update retry documentation and small repository-local integration checks.
|
||
|
||
Acceptance: fixture workflow evidence verifies all three filenames, full
|
||
manifest, matching rerun, and partial/ambiguous delivery. Existing historical
|
||
tags/pages/assets are untouched and source publication waits for no delivery.
|
||
|
||
## Stage 30: Audit the completed target state and documentation
|
||
|
||
Status: Pending. Depends on Stage 29.
|
||
|
||
1. Map each feature-roadmap responsibility to its implemented owner and tests.
|
||
Verify both public facades, source-only behavior, candidate checks, exact
|
||
publication, runtime injection, selected targets, hosted content verification,
|
||
partial recovery, and Woodpecker integration against current source.
|
||
2. Review the six migrations against both architecture success criteria: shared
|
||
infrastructure was removed and one coherent model was adopted. Count actual
|
||
removed scripts/tests, retained product checks, and new ReleaseKit code
|
||
separately; do not present the historical estimate as measured savings.
|
||
3. Check current documentation owners, links, examples, dependency attribution,
|
||
license texts, and maintainer runbooks. Record live integration verification
|
||
separately from local acceptance, including anything awaiting activation.
|
||
4. Update feature status and this plan from evidence. Retire completed execution
|
||
details during release preparation while preserving target intent, deferred
|
||
decisions, and useful navigation.
|
||
|
||
Acceptance: each roadmap responsibility has direct source and behavioral
|
||
evidence, each migrated repository retains only justified product checks and
|
||
small wiring coverage, and no unimplemented or unverified responsibility is
|
||
marked complete. Run affected suites according to their policies; add no new
|
||
permanent release matrix or synchronization gate.
|
||
|
||
## Coverage of the feature roadmap
|
||
|
||
| Target responsibility | Implementing stages |
|
||
| --- | --- |
|
||
| Two public facades and small runtime dependencies | 1–3, extended in 10–11 and 17 |
|
||
| Stable version and committed note identity | 5 |
|
||
| Candidate capture, one validation, mutable guards | 5–8, 11 |
|
||
| Authoritative endpoint and remote ref state | 6–8 |
|
||
| Annotated object publication and failure recovery | 7–9 |
|
||
| ReleaseKit source-only bootstrap/runbook | 9 |
|
||
| Shared version injection and selected cross-builds | 2, 10–11 |
|
||
| Native smoke, empty target sets, consistent names | 10–11 |
|
||
| Hosted page/note creation and immutable content | 14–17 |
|
||
| Full checksums, comparison, partial/additive retries | 15–17 |
|
||
| Woodpecker tag integration and separate statuses | 18, 20, 26, 29 |
|
||
| PromptKit and Scriptorium pilots | 12–13, 19–20 |
|
||
| ConfigKit, Notarius, Audita, Narratio adoption | 21–29 |
|
||
| Actual infrastructure reduction and canonical docs | 30 |
|
||
|
||
## Open Questions
|
||
|
||
The core implementation choices above are complete for the recommended design.
|
||
These maintainer decisions affect adoption and live use; do not fill in unknown
|
||
release pins or silently broaden deliverables.
|
||
|
||
### Which immutable ReleaseKit versions should consumers pin?
|
||
|
||
Required before Stage 12, and refreshed before Stage 18 and runtime migrations.
|
||
|
||
**Recommended:** publish a first source release such as `v0.1.0` after Stage 11,
|
||
then a delivery-capable source release after Stage 17. Verify version availability
|
||
at preparation time and use the actual published pins in profiles' accompanying
|
||
installation instructions, CI provisioning, and application module dependencies.
|
||
This gives the publication pilots an early usable tool and lets later delivery
|
||
and runtime adopters depend on documented versioned contracts. Publication is a
|
||
separate maintainer-authorized action under the release policy.
|
||
|
||
**Viable alternative:** make immutable source-commit/pseudo-version pins available
|
||
for the pilots and publish the first numbered release after Stage 17. This
|
||
supports integration feedback before a numbered release, at the cost of more
|
||
operator bookkeeping and less friendly installation instructions. Neither
|
||
approach commits local checkout replacements or claims an unpublished version
|
||
exists. Record the selected pins here before dependent migration stages proceed.
|
||
|
||
### Should source-only projects also receive hosted Gitea release pages?
|
||
|
||
This decision is required only if adopting pages for PromptKit, ConfigKit,
|
||
Notarius, or ReleaseKit; their current plan stages preserve source-only delivery
|
||
without hosted-page requirements.
|
||
|
||
**Recommended:** retain their existing delivery scope initially. Support explicit
|
||
zero-asset hosted delivery in ReleaseKit, while using the three existing binary
|
||
publishers to establish its behavior. This meets the requested standardization
|
||
without adding credentials, CI operations, or a new deliverable to other projects.
|
||
|
||
**Viable alternative:** declare a hosted note page for every project, with zero
|
||
binary assets where appropriate. This gives uniform forge presentation and uses
|
||
the same delivery API, but needs deliberate local release-policy changes,
|
||
credentials, and responsibility for retries. If selected, add a small adoption
|
||
stage for each affected project before completing Stage 30.
|