From 536a57916f6565ae8194c4563577dfcebd6cfb69 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Tue, 6 Oct 2026 14:27:17 +0000 Subject: [PATCH] Retire completed roadmaps and preserve adoption work --- README.md | 13 +- docs/development.md | 5 +- docs/roadmap/implementation.md | 997 --------------------------------- docs/roadmap/policy.md | 183 ------ docs/roadmap/releasekit.md | 48 +- docs/roadmap/remediation.md | 428 -------------- ideas.md | 4 +- 7 files changed, 42 insertions(+), 1636 deletions(-) delete mode 100644 docs/roadmap/implementation.md delete mode 100644 docs/roadmap/policy.md delete mode 100644 docs/roadmap/remediation.md diff --git a/README.md b/README.md index d327960..f04ef90 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,8 @@ tagged-source delivery API, and `version`, `check`, `publish`, `build`, and `deliver` commands are implemented. ReleaseKit's source-only maintainer procedure and prepared Woodpecker workflow for hosted note-page delivery are documented. ReleaseKit does not declare binary deliverables. The -[product roadmap](docs/roadmap/releasekit.md) and -[implementation plan](docs/roadmap/implementation.md) describe their selected -behavior and sequence. +[product roadmap](docs/roadmap/releasekit.md) records remaining adoption and +deployment work. Run the offline Go test suite from the repository root with: @@ -41,8 +40,8 @@ failure recovery. ## Documentation -- [ReleaseKit proposal](docs/roadmap/releasekit.md): selected publication, builds, - version injection, and delivery conventions, with the implementation plan. +- [Product roadmap](docs/roadmap/releasekit.md): consumer adoption goals and + remaining release and deployment work. - [Contributor guide](docs/development.md): orientation, validation, and selective policy reading. - [CLI contract](docs/cli.md): the `version`, `check`, `publish`, `build`, and @@ -65,8 +64,8 @@ failure recovery. - [Architecture policy](docs/policy/architecture.md): responsibility and dependency boundaries for development. - [ADR 0001](docs/adr/0001-public-facade.md): the accepted public facade decision. -- [Policy adoption roadmap](docs/roadmap/policy.md): completed adoption and the - current source-release path. +- [Policy provenance](docs/policy/meta.md): adopted policy sources and update + guidance. ReleaseKit is licensed under the [LGPL v3.0 or later](COPYRIGHT). diff --git a/docs/development.md b/docs/development.md index ea7dab7..c675def 100644 --- a/docs/development.md +++ b/docs/development.md @@ -50,8 +50,9 @@ go run ./internal/apicheck ``` See the [candidate check guide](consumers/check.md), [build consumer guide](consumers/build.md), -[internal package inventory](internal/overview.md), and [implementation plan](roadmap/implementation.md) -for current implementation progress. +and [internal package inventory](internal/overview.md) for implemented behavior +and capability ownership. The [product roadmap](roadmap/releasekit.md) records +remaining adoption and deployment work. For prose changes, review the diff and check local links, fragment destinations, provenance, template residue, and consistency with current repository contents. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index 2e61168..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,997 +0,0 @@ -# ReleaseKit staged implementation plan - -Status: Complete. Stages 1–18 are complete. - -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 `6c2695f`. 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 provide design evidence; this implementation sequence -changes ReleaseKit only. Consumer migrations and measurement of deleted consumer -infrastructure belong to later adoption work. Consult code through the knowledge -graph, indexing a repository when necessary. Documents, scripts, and CI -configuration may be read directly under the discovery instructions. - -## Scope and completion - -Deliver the complete initial library, executable, configuration, shared build -and delivery mechanics, Woodpecker examples, and ReleaseKit's own prepared -release wiring. Hosted Gitea release pages are part of the selected standard -for every project, including source-only projects. Source-only delivery uses -the committed release note and zero binary assets; it needs no binary build or -checksum manifest. - -Proceed through all stages using the local checkout and controlled fixtures. -No stage depends on an intermediate release, published tool/runtime pin, -consumer pilot, external service action, or human review. Ordinary automated -development checks accompany implementation under the testing policy. - -After the complete initial implementation, the maintainer will review the -architecture, address discovered issues, and then choose the broader testing -plan and next steps. Consumer adoption, live integration testing, secret -provisioning, CI activation, and actual publication are outside this sequence. - -## 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. - Apply the selected scope and decisions throughout the sequence. 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. -- Keep the implementation self-contained. Build the tool from this checkout; - temporary fixture modules may use local replacements. Integration templates - accept an operator-selected immutable tool pin for later deployment, without - requiring one to complete this plan or claiming that a release already exists. -- Complete stages with local implementation commits and controlled checks. - Prepare runnable automation and deployment instructions without activating - live workflows. Distinguish implemented integration from verified live use. - Finish the whole sequence before the maintainer's architecture review; add no - intermediate approval or external-action checkpoint. - -## 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 `/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. - -This composite profile shows the implemented fields together; working -[source-only](../../examples/releasekit.json) and -[binary-producing](../../examples/releasekit-binary.json) profiles are maintained -under `examples/`: - -```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" - } -} -``` - -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; -source-only checks and publication need neither a main package nor credentials. -Hosted page delivery requires a destination and token for source-only profiles -as well as binary-producing profiles. -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 `. -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/.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 -`:refs/tags/` 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 `---`, 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 -` ` 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, hosted delivery creates -the required note page without a binary manifest or build receipt. An absent -build specification is equivalent to zero targets for source-only delivery. -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. Implement the operations described here against -local fixtures and record them in the integration guide. Verification against -the deployed host belongs to later live testing and is not needed to complete -this sequence. 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 image -and an explicit tool preparation step. Provide source-only and binary-producing -examples. Consumer templates accept an operator-selected immutable ReleaseKit -source pin for deployment; template preparation and local execution use the -implementation checkout and require no published pin. Prepare consumer module -caches separately, then run builds and delivery with offline Go execution. -This honors ReleaseKit's source-only distribution; a dedicated ReleaseKit -container image would require a separate deliverable decision. Use a Go image -that satisfies the repository's module requirements. - -ReleaseKit's own prepared workflow builds `cmd/releasekit` from its tagged -checkout using the local toolchain and delivers its hosted note page. It needs -no previously released executable and produces no distributed binary assets. -Prepare this workflow locally; activation belongs to the later next-step plan. - -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. For binary -profiles, the build step writes to ignored `dist` and the delivery step shares -the workspace. Source-only workflows call delivery directly without an artifact -build step. Supply the Gitea token only to delivery from a Woodpecker secret. -Document operator substitution of image digests and source pins for eventual -consumer deployment. 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: Complete. 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. - -Completion evidence: added the Go 1.25.0 module and documented root facade, -updated the README and developer guide to describe the implemented boundary and -offline test command, and confirmed module loading and `go test ./...` with -network access disabled. The module has no external dependencies; existing -LGPL licensing and attribution notices remain consistent. - -## Stage 2: Implement the runtime version facade - -Status: Complete. 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. - -Completion evidence: implemented `buildinfo.Version`, its private injected -string and main-module fallback, and the internal linker-symbol contract. Unit -tests cover injection precedence and missing, development, and stable main -module metadata. Built and ran a separate consumer executable from source and -with an injected stable version using network-disabled Go commands; both -reported the selected value. CLI tests cover its version line, and the CLI's -dependency closure contains no orchestration package. Added runtime consumer -guidance and documented the command contract. - -## Stage 3: Protect public contracts and dependency direction - -Status: Complete. 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. - -Completion evidence: added `internal/apicheck`, which loads compiled exports -from `go list -deps -export` and inspects signatures, fields, aliases, generic -constraints, and pointer and value method sets through `go/types`. The checks -pass for both public facades and enforce internal import direction and the -runtime dependency boundary. Negative fixtures detect leaked types, aliases, -callbacks, generic constraints, and promoted implementation methods; a private -implementation field and selected standard-library contracts pass. Added the -checker command and internal package inventory to the canonical developer docs. - -## Stage 4: Implement profile loading and command adaptation - -Status: Complete. 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. - -Completion evidence: added strict profile decoding, repository-relative and -absolute profile resolution, required product and command diagnostics, and -direct check argument adaptation. Added a cancellable `os/exec` runner with -working directory, inherited environment plus child-only overlays, stdout, -stderr, and preserved exit errors. Tests cover spaced paths and arguments, -environment isolation, missing executables, exit failures, cancellation, and -invalid profiles. Added a profile example and canonical CLI, configuration, and -internal package documentation. - -## Stage 5: Capture and validate one local candidate - -Status: Complete. 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. - -Evidence: `internal/candidate` validates stable versions and committed note -identity, captures a clean `main` commit, runs either the offline default or the -configured callback once, and rechecks local mutable state. The public -`releasekit.Check` API and `releasekit check` command provide the local -diagnostic. Temporary Git repositories cover the acceptance cases; offline -`go test -count=1 ./...` and `go run ./internal/apicheck` pass. - -## Stage 6: Resolve and inspect the authoritative endpoint - -Status: Complete. 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. - -Evidence: `internal/git` captures effective push destinations through Git, -rejects multiple distinct destinations, verifies scoped URL rewriting, and -queries exact main and version-tag refs. A candidate check requires main to -equal the captured commit and the version tag to be absent. Local bare remote -tests cover separate fetch/push URLs, both rewrite modes, missing main, an -existing tag, main ahead and behind, endpoint changes, unreadable remote state, -and unchanged persistent config and refs. - -## Stage 7: Create and push the exact annotated tag - -Status: Complete. 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. - -Evidence: the public `releasekit.Publish` API captures the committed note, -validates once between exact remote guards, creates an unsigned annotated tag, -rechecks local and remote state, and pushes only the captured tag object. Bare -remote tests verify the note bytes, peeled commit, tag object, unchanged branch -and unrelated refs, disabled follow-tags and mirror expansion, validation count, -remote conflicts, and retained local tags after push error; Stage 8 adds outcome -classification through remote reconciliation. - -## Stage 8: Resolve rejected and ambiguous publication - -Status: Complete. 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. - -Evidence: failed tag pushes receive one bounded exact-tag query. Matching object -identity returns published; absence returns not_published with the original push -error; a different object returns conflict; query failure returns unknown while -preserving the push cause. Tests cover rejection by a bare remote's receive -hook, an installed conflicting tag, unavailable reconciliation, and a lost -acknowledgment after the bare remote accepted the tag while the caller context -was canceled. Query counts confirm one recovery read after errors and none after -a successful push. -Tests also verify that a remote branch change during validation and a changed -local tag before push prevent publication. - -## Stage 9: Expose publication and document ReleaseKit bootstrap - -Status: Complete. 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. - -Evidence: `publish` runs the public publisher with the CLI signal context, -selected progress output, final commit and tag-object output, and separate exit -status for unresolved outcomes. A temporary committed profile runs the offline -test command and publishes to a local bare remote. ReleaseKit's root profile, -entry script, CLI and configuration guides, development guide, and maintainer -runbook describe source-only publication and exact-object recovery. The -runbook's dependency preparation is separate from offline validation. No real -ReleaseKit release was published. - -## Stage 10: Build selected targets with shared version injection - -Status: Complete. 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. - -Evidence: `releasekit.Build` and `internal/build` compile Linux amd64, Linux -arm64, and macOS arm64 artifacts using the shared linker symbol and prepared -local Go environment. The consumer fixture imports `buildinfo` and reports the -injected version through its `version` invocation. Results retain the observed -source commit, compiler identity, normalized targets, absolute paths, filenames, -and SHA-256 digests. Tests cover host selection despite ambient cross-target -variables, empty target sets, existing output preservation, partial target -failure, missing packages, incorrect version output, unsafe names, and -cancellation with completed artifacts retained. No byte-reproducibility or -cross-platform execution guarantee is added. - -## Stage 11: Integrate candidate builds and artifact command - -Status: Complete. 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. Continue directly to hosted delivery implementation; -no publication or consumer pilot is needed to complete this stage. - -## Stage 12: Find and create Gitea release pages - -Status: Complete. Depends on Stage 11. - -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 13: Inspect asset and manifest content - -Status: Complete. Depends on Stage 12. - -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 14: Upload missing assets and report partial delivery - -Status: Complete. Depends on Stage 13. - -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 15: Expose tagged-source delivery through the facade and CLI - -Status: Complete. Depends on Stage 14. - -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 declared tagged-source artifacts in temporary storage before uploading. - An absent build specification or empty target set selects page-only delivery: - skip the builder, native smoke, receipt requirement, and manifest generation. -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: facade/CLI fixtures cover both page-only delivery and binary delivery -from tagged source to a local server, with content-aware reruns. Page-only -delivery preserves the complete note, needs no main package or receipt, and -performs no Go build or asset upload. 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. - -Evidence: `releasekit.Deliver` and `releasekit deliver` now verify lightweight or -annotated local tags from clean, attached or detached checkouts, compare the -hosted tag commit, and use the note read from the tagged commit. The CLI loads -delivery credentials only for delivery; it builds selected tagged-source -artifacts in temporary storage or verifies a supplied build receipt and its -artifact hashes before calling the facade. Page-only fixtures create and reuse -the complete note without a main package, receipt, manifest, build, or upload. -Binary fixtures build a tagged-source executable, upload it with `SHA256SUMS`, -and accept matching page and asset content on rerun. Local server tests verify -that wrong hosted and local commits, stale build settings, tampered receipt -assets, and missing credentials prevent remote writes; the tag remains intact -after delivery failure. `go test ./...`, `go run ./internal/apicheck`, and the -Markdown whitespace check pass. All delivery checks use a local HTTP fixture; -no live Gitea service or credentials were used. - -## Stage 16: Provide the common Woodpecker integration - -Status: Complete. Depends on Stage 15. - -1. Add maintained source-only and binary-producing tag-pipeline templates. - Parameterize the Go image and immutable ReleaseKit source pin for eventual - deployment, with explicit installation/cache preparation and a delivery - secret. Document required template inputs rather than inventing a published - pin. 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 source-only template delivers the note - page directly; the binary template first builds its declared assets. Neither - workflow executes the publisher. -4. Exercise both command sequences locally with a tool built from this checkout, - fixture repositories, and a local server. Substitute the local executable for - the templates' installation step during development checks. Check YAML using - locally available tooling or static inspection; no live runner or new - external validator is needed to complete the stage. - -Acceptance: the maintained commands reach common delivery for both profile types -and common builds for declared binary targets, with the selected version and -commit. Secrets enter only the delivery step. Agent-performed static YAML checks -and local command evidence are recorded accurately. No published tool pin, -container pull, configured secret, or live runner is a stage prerequisite. -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. - -Evidence: maintained source-only and binary tag workflows are in -`examples/woodpecker/`. Both parameterize the Go image and immutable ReleaseKit -commit through their matrix entries, verify the fetched tag against the runner -commit, and keep shared output under the locally ignored `.releasekit/` -directory. Only the delivery step maps the configured Woodpecker secret to the -CLI token variable. The source-only workflow delivers the note page; the binary -workflow prepares module caches, builds declared targets offline, and passes -the build receipt and assets into delivery. The delivery guide covers template -inputs, source publication versus delivery status, and retries against the same -tag. A test builds the CLI from this checkout and exercises both workflows' -delivery command sequences against fixture repositories and a local HTTP -server; it substitutes the built executable for the installation command. Both -YAML files parse with locally available PyYAML 6.0.3, and static checks confirm -their tag filters, step layout, and delivery-only secret mapping. `go test ./...`, -`go run ./internal/apicheck`, and the Markdown whitespace check pass. No live -Woodpecker runner, image pull, secret, or hosted delivery service was used. - -## Stage 17: Prepare ReleaseKit's own hosted-page delivery - -Status: Complete. Depends on Stage 16. - -1. Extend ReleaseKit's source-only profile with its Gitea destination and token - environment name. Keep the build target set empty and retain its selected - offline candidate suite. No distributed executable or binary manifest is - introduced. -2. Prepare a repository-specific Woodpecker workflow under the maintained - examples, using the tagged checkout to build the local release tool and call - page-only delivery. Keep it outside active CI discovery during this sequence. - Document where to place it for later activation and how to supply its secret. -3. Update the release policy's deliverable declaration and `docs/release.md` - together to identify the hosted note page, automation responsibility, and - page-delivery retry command. Source completion remains the exact tag push. -4. Exercise the prepared command sequence against a temporary tagged repository - and local HTTP server. Retain the note's complete body, including licensing - footer, on the hosted page. - -Acceptance: ReleaseKit's source-only example creates a hosted page and accepts -an identical rerun without building consumer binaries, generating a manifest, -requiring a receipt, or consulting a previously released tool. Delivery failure -leaves source status unchanged. Workflow preparation requires no real tag, -credentials, remote push, CI activation, or maintainer checkpoint. - -Evidence: ReleaseKit's root profile identifies its Gitea destination and -`RELEASEKIT_GITEA_TOKEN`, preserves the offline default test suite, and declares -no build targets. The repository-specific Woodpecker example remains under -`examples/` and builds the CLI from the fetched, commit-checked tag before -page-only delivery; the release procedure documents later activation and secret -configuration, source-tag completion, and same-tag retry. A local integration -test clones and tags a temporary copy of the repository, builds the CLI from -that tag, and exercises delivery against a local HTTP server. It verifies a -hosted-tag failure leaves the source tag intact, then checks page creation and -an identical rerun without assets; the complete note body, including its three -license links, is preserved. No real tag, push, credential, or hosted service -was used. - -## Stage 18: Complete the initial implementation and handoff documentation - -Status: Complete. Depends on Stage 17. - -1. Map each initial capability in the feature roadmap to its implemented owner - and existing behavioral evidence. Record the concrete package and dependency - inventory, both supported facades, and their implemented responsibilities in - the canonical internal and consumer documentation. -2. Finish current API, CLI, configuration, integration, example, development, - and release documentation. Check links and consistency with actual behavior; - keep licensing and attribution accurate for incorporated material. -3. Run the established offline default suite and relevant existing boundary - checks for the assembled implementation. Resolve implementation defects - within this scope without adding a new permanent release matrix or live - testing requirement. -4. Record the completed initial implementation and evidence in this plan. - Identify prepared integrations whose live operation remains unverified and - hand off the implementation for the maintainer's subsequent architecture - review. Keep consumer migrations and their anticipated code savings marked - as future adoption work. - -Acceptance: the initial library and executable provide check, publication, -build, runtime version access, page-only and binary delivery, partial/uncertain -recovery, and prepared Woodpecker integration. The documentation describes the -implemented boundary accurately. Completion depends on local implementation -and development evidence; architectural review, a broader testing plan, -consumer migrations, and release/deployment decisions follow this sequence. - -Evidence and handoff: `docs/internal/overview.md` records both public Go -facades, all 14 implemented Go packages, the absence of third-party module -dependencies, capability ownership, and representative behavioral tests. The -README and canonical CLI, configuration, consumer, integration, development, -and release documents describe the implemented behavior; the policy and product -roadmaps no longer present completed facade, delivery, or workflow work as -pending. `go test ./...`, `go run ./internal/apicheck`, local Markdown link and -fragment checks, and prose whitespace checks pass. All three maintained -Woodpecker examples parse with local PyYAML 6.0.3, with the token mapped only in -each delivery step. Local Git and HTTP fixtures exercise source-only delivery, -binary delivery, publication recovery, and the ReleaseKit tagged-source workflow. - -The Woodpecker workflows remain prepared, not activated. No live runner, -configured deployment secret, immutable deployment pin, hosted Gitea delivery, -or ReleaseKit source release was used or verified. Consumer migrations and -measurement of removed consumer infrastructure remain future adoption work. -The implementation is ready for the maintainer's subsequent architecture -review; broader testing and release or deployment decisions remain outside this -completed implementation sequence. - -## Coverage of the feature roadmap - -| Initial target responsibility | Implementing stages | -| --- | --- | -| Two public facades and small runtime dependencies | 1–3, extended in 10–11 and 15 | -| 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, 17 | -| Shared version injection and selected cross-builds | 2, 10–11 | -| Native smoke, empty target sets, consistent names | 10–11 | -| Hosted page/note creation, including source-only projects | 12, 15, 17 | -| Full checksums, comparison, partial/additive retries | 13–15 | -| Prepared Woodpecker workflows for both delivery profiles | 16–17 | -| Complete initial implementation and canonical documentation | 18 | - -Consumer infrastructure reduction and convergence on the shared standard remain -feature-roadmap adoption goals. Their migration sequence, real-world testing, -and measured savings will be determined after the initial architecture review. - -## Open Questions - -None block this initial implementation sequence. The maintainer has selected -hosted pages for source-only projects and deferred pilots, releases, consumer -adoption, and broader testing decisions until after implementation and the -subsequent architecture review. Actual release pins and deployment credentials -are inputs to later adoption; no stage requires them. diff --git a/docs/roadmap/policy.md b/docs/roadmap/policy.md deleted file mode 100644 index 7ff9c2a..0000000 --- a/docs/roadmap/policy.md +++ /dev/null @@ -1,183 +0,0 @@ -# Adopt the policy framework - -Status: Policy adoption complete. Source publication, its maintainer runbook, -and prepared hosted note-page delivery are implemented; no ReleaseKit release -has been published. Binary distribution remains deferred. - -Date: 2026-10-05 - -## Purpose and scope - -Standard Repository Policies are adopted into ReleaseKit as locally maintained -rules for an opinionated Go library and its proposed release executable. The -adoption preserves the project's existing licensing choice, supports deliberate -standardization of release behavior, and keeps documentation accurate about what -has been implemented. - -This roadmap covers policy adoption, contributor navigation, documentation -ownership, licensing notices, and the preparation of ReleaseKit's own release -procedure. Product implementation and consumer migrations belong to the separate -[ReleaseKit proposal](releasekit.md). - -## Upstream baseline and references - -Use upstream commit `d84a38ebab26f048cafbe59a2246700c35d29843`. The local -`../policy` checkout and upstream `main` matched that revision during the review. -PromptKit and ConfigKit adopted the same baseline. - -Follow the [adoption guide at the selected revision](https://gitea.maximumdirect.net/eric/policy/src/commit/d84a38ebab26f048cafbe59a2246700c35d29843/docs/adoption.md). -Copy applicable policies locally and customize them. Retain each file's exact -upstream provenance; later upstream changes become local rules through deliberate -review and adoption. Git history is sufficient to record this process. - -Useful library adaptations include -[ConfigKit's architecture policy](../../../ConfigKit/docs/policy/architecture.md), -[PromptKit's architecture policy](../../../promptkit/docs/policy/architecture.md), -and their documentation, testing, and attribution policies. Use these as examples -of adaptation rather than copying their product-specific requirements. - -## Policy adaptations - -All seven policies are adopted under `docs/policy/`: - -| Policy | Base version | ReleaseKit adaptation | -| --- | --- | --- | -| `meta.md` | 1.0 | Retain local authority, per-document adoption provenance, and upstream update navigation. | -| `agents.md` | 1.3 | Retain proportionate implementation and local commit practices. Add the libraries' clarification that implementation, tests, and agent-authored plans do not independently establish new contracts. | -| `architecture.md` | 1.3 | Define the library, proposed executable, consumer responsibilities, external effects, and dependency boundaries. | -| `testing.md` | 1.3 | Retain behavioral, deterministic, offline testing. Prioritize publication integrity, ambiguous outcomes, partial delivery, cross-builds, and version injection as those features are implemented. | -| `documentation.md` | 1.11 | Assign exact exported Go contracts to declarations and GoDoc, workflows to consumer guides, and proposals to roadmap documents. Add CLI and integration owners when those interfaces exist. | -| `oss.md` | 1.8 | Preserve the library licensing choice, apply the attribution format, and identify separately licensed copied policy material. | -| `release.md` | 1.4 | Govern releases of ReleaseKit itself, with explicit deliverables and justified checks. Distinguish its maintainer procedure from the release standard offered to consumers. | - -## Adopted architectural constraints - -The [architecture policy](../policy/architecture.md) owns the adopted boundaries, -including [ADR 0001](../adr/0001-public-facade.md) and the runtime version -constraints. The following summarizes those rules for this adoption record. - -Evaluate ReleaseKit against both of ConfigKit's relevant success criteria: -applications should delete substantial infrastructure, and consumers should adopt -one consistent set of deliberately selected conventions. - -- ReleaseKit owns the selected publication, version injection, build, and delivery - conventions. Consumers supply product identity, main package, selected targets, - and application-specific checks. -- Consumers use the root `releasekit` orchestration facade and the lightweight - `buildinfo` runtime facade. Both packages own their public contracts and - delegate through private state and explicit conversions to internal - implementation. ReleaseKit builds and tests independently - of the consuming repositories and does not depend on their private packages. -- Git, filesystem, Go toolchain, and Gitea effects have proportionate boundaries - and occur through explicit operations. Package layout and abstractions should - serve those boundaries without requiring an application framework. -- The library returns meaningful errors and publication outcomes. The executable - handles command parsing, output, and exit codes. -- The `buildinfo` facade provides runtime version access through a lightweight - dependency graph. ReleaseKit's builder and runtime implementation own version - injection together. - -Architecture policy may govern future development. Concrete package inventory, -API semantics, and implemented behavior must be documented when they exist. - -## Adoption stages - -### 1. Copy and tailor policies - -- [x] Copy the seven policies from the selected baseline. -- [x] Preserve each `Base Policy Version`, set `Last Updated` to the actual - adoption date, and add an `Upstream Source` link to that file at the full commit. -- [x] Customize the policies for ReleaseKit and remove their `Base Policy - Template` sections. -- [x] Adapt upstream `agents/AGENTS.md` into root `AGENTS.md`, preserving the - existing knowledge-graph discovery instructions. -- [x] Create `docs/development.md` with contributor orientation and the selective - policy reading guide. Route tasks to applicable policies instead of requiring - the entire suite for every task. - -### 2. Establish documentation ownership - -- [x] Move the substantive contents of `ideas.md` to - `docs/roadmap/releasekit.md`, preserving the proposal, and retain `ideas.md` as a - navigation pointer. Update this roadmap's proposal link in the same change. -- [x] Update README with accurate current status and navigation. -- [x] Define ownership for GoDoc, consumer guidance, architecture constraints, - internal implementation, release procedures, ADRs, and unfinished work. -- [x] Reserve consumer, CLI, configuration, integration, and internal ownership - in the documentation policy. Their documents await corresponding implementation; - no empty owners or speculative command references were created. - -### 3. Complete notices and attribution - -- [x] Add root `COPYRIGHT` using the upstream library example and verified project - details. The grant is `LGPL-3.0-or-later`, consistent with the existing library - licensing choice and the two library examples. -- [x] Restore the complete, verbatim LGPLv3 and incorporated GPLv3 texts in - `LICENSE`; the original contained reformatted text and a customized appendix. - Keep project-specific grant statements in `COPYRIGHT`. -- [x] Add `docs/oss/attribution.md` with the supplied policy attribution entry, - describing the actual adapted policies, agent orientation, and reading guide. -- [x] Copy the CC-BY-SA 4.0 text to `docs/oss/licenses/CC-BY-SA-4.0.txt` and identify - the copied material's separate licensing scope in `COPYRIGHT`. -- [x] Add README links to the project grant and attribution document. Keep source - and notice links pinned to the adopted commit and reference examples upstream. - -The library's selected license remains the project grant. A future executable -does not automatically acquire a different license merely because the upstream -policy has separate defaults for applications and libraries. - -### 4. Define ReleaseKit's own release path - -- [x] Adopt the general versioning, compatibility, integrity, immutability, and - successful-tag-push completion rules. -- [x] Select the immutable source tag as the source-completion point and the - hosted note page as a separate asynchronous deliverable. Supporting downstream - cross-builds does not declare ReleaseKit binaries. -- [x] Add `docs/release.md` alongside the first working publication command, - documenting real prerequisites, authoritative remote, branch, validation, - publication, and failure recovery. -- [x] Account for first-release bootstrap: the initial publication command must - run from the captured candidate source with dependencies prepared separately. - The first release uses that source execution path before a released ReleaseKit - tool exists. The maintainer procedure documents the command and the temporary - repository integration test exercises the same CLI workflow. -- [ ] Add executable delivery declarations and target checks when corresponding - deliverables exist. Keep source completion and asynchronous delivery status - separate. This task is deferred unless executable deliverables are selected. - -The publication command, its automated guards, offline candidate validation, -executable maintainer runbook, and prepared hosted-page workflow are implemented. -This adoption does not claim that a ReleaseKit version has been published. - -## Validation and completion - -Review provenance, attribution scope, faithful license texts, template residue, -local links, whitespace, and consistency with implemented repository behavior. -Documentation-only adoption should use those checks; executable commands and -examples added later require appropriate execution checks. - -Adoption is complete when the tailored policy set, contributor navigation, -documentation ownership, and licensing notices are coherent and verified. The -source-publication command and hosted-page delivery are implemented; actual -publication and binary distribution remain outside policy adoption. - -Do not inherit PromptKit's or ConfigKit's extra release gates automatically. -Select additional checks only for identified ReleaseKit risks, recording their -justification in the adopted policy. Upstream synchronization, recurring license -approval, and CI polling are not additional adoption or release gates. - -## Adoption result - -The seven policies, root agent orientation, developer reading guide, documentation -ownership, project grant, attribution, license texts, source publication command, -maintainer runbook, and prepared hosted-page delivery are in place. The product -proposal lives at `docs/roadmap/releasekit.md`; `ideas.md` remains a navigation -pointer. Binary distribution is deferred, and no ReleaseKit release has been -published. - -Verification covers local file and fragment links, per-policy source revision and -base version, removed template adoption sections, attribution scope and pinned -notice destinations, verbatim license bytes, and prose whitespace. The preserved -ADR decision and relocated proposal are checked against their pre-adoption source. -ReleaseKit's source publication command, runbook, and hosted-page deliverable are -implemented; binary delivery declarations remain deferred under stage 4. diff --git a/docs/roadmap/releasekit.md b/docs/roadmap/releasekit.md index 0c66e7e..0347b88 100644 --- a/docs/roadmap/releasekit.md +++ b/docs/roadmap/releasekit.md @@ -1,16 +1,16 @@ # ReleaseKit: shared release process -This proposal records a review of PromptKit, ConfigKit, Audita, Notarius, -Narratio, and Scriptorium on 2026-09-29. The initial library, CLI, build and -delivery paths, and prepared Woodpecker examples are implemented; the -[implementation plan](implementation.md) records the completed boundary and -evidence. The public facade architecture is accepted in -[ADR 0001](../adr/0001-public-facade.md) and implemented for runtime version, -candidate validation, source publication, selected-target builds, and tagged- -source delivery. -The [implementation plan](implementation.md) owns ordered stages, execution -instructions, acceptance checks, and implementation status. Consumer migration -and measurement of local infrastructure reduction remain future adoption work. +Status: Initial implementation, policy adoption, and architecture remediation +are complete. Consumer adoption, publication, and live integration work remain. + +This roadmap records the shared release-process opportunity identified in +PromptKit, ConfigKit, Audita, Notarius, Narratio, and Scriptorium on 2026-09-29, +and the remaining adoption goals. The [internal package inventory](../internal/overview.md) +records implemented capability owners and behavioral evidence. The +[architecture policy](../policy/architecture.md) and +[ADR 0001](../adr/0001-public-facade.md) own the facade boundaries and rationale. +The completed implementation, policy adoption, and remediation plans are +preserved in Git history. ## Opportunity @@ -96,8 +96,8 @@ and GoDoc own exact public API contracts; additional public packages and extension interfaces require a deliberate decision grounded in durable consumer needs. -Compiled-export and dependency checks will protect facade ownership. -External-package behavioral tests will protect error identity, value ownership, +Compiled-export and dependency checks protect facade ownership. +External-package behavioral tests protect error identity, value ownership, callback lifetime, and observable outcomes across forwarding and conversions. ## Shared tool boundary @@ -202,10 +202,24 @@ Existing published tags, notes, pages, and assets retain their historical conten Consumer policy and procedure changes should describe the deliberately adopted standard and its compatibility impact. Adoption should demonstrate reduced local -infrastructure and one coherent release model. The implementation plan owns the -complete initial ReleaseKit implementation and its development evidence. -Architecture review follows that implementation; broader testing and consumer -migration steps will be chosen afterward. +infrastructure and one coherent release model. + +## Remaining work + +- Prepare and publish the first ReleaseKit source release under the + [maintainer procedure](../release.md), then deliver its hosted note page. +- Choose the broader consumer integration test plan and migration sequence. + Evaluate API clarity, product-specific checks, and the infrastructure removed + from each consuming repository. +- Select immutable ReleaseKit deployment pins and Go image digests for consumer + workflows. Provision delivery credentials and activate the prepared Woodpecker + workflows 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. ## Reviewed implementations diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md deleted file mode 100644 index 588460f..0000000 --- a/docs/roadmap/remediation.md +++ /dev/null @@ -1,428 +0,0 @@ -# ReleaseKit implementation review and remediation - -Status: Complete. R1–R10 are resolved; resolution notes record the fixes and -verification. - -Date: 2026-10-06 - -## Review scope and evidence - -Reviewed the initial implementation from `cc7ca47` through `539877e`, including -the public facades, internal publication/build/delivery paths, executable and -profile/receipt adapters, boundary checker, tests, maintained workflows, and -current documentation. The worktree was clean at the start of the review. -The [feature roadmap](releasekit.md), [implementation plan](implementation.md), -[ADR 0001](../adr/0001-public-facade.md), and applicable adopted policies define -the intended scope. An agent-authored implementation or assertion does not -independently authorize an additional restriction. - -The uncached offline suite passed with `go test -count=1 ./...`, using -`GOWORK=off`, `GOPROXY=off`, `GONOPROXY=none`, `GOSUMDB=off`, and -`GOTOOLCHAIN=local`. The compiled-export and dependency checker passed with -`go run ./internal/apicheck`. Passing these checks does not resolve the findings -below: controlled reproductions exposed behavior outside their current coverage. -Reproductions used temporary consumer modules, local Git repositories and bare -remotes, local HTTP servers, and one temporary Go test overlay. They changed no -tracked implementation files and used no real credentials or publication service. - -The prepared workflow syntax was also compared with the official Woodpecker -[matrix](https://woodpecker-ci.org/docs/usage/matrix-workflows) and -[environment](https://woodpecker-ci.org/docs/usage/environment) references. -Live CI, live Gitea delivery, consumer migrations, and measured consumer code -reduction remain intentionally deferred; their absence is not a finding. - -## Initial architecture assessment - -One Go module exposes two supported packages. The root `releasekit` package -owns `Check`, `Publish`, `Build`, `Deliver`, and their public request/result -values. `buildinfo.Version` forwards into a small standard-library runtime -implementation. The builder and runtime share a private injection-symbol -contract. Public signatures own their named types and expose no internal -implementation types. - -`cmd/releasekit` calls the supported facades; command-owned internal helpers -parse profiles, execute configured checks, and handle private receipts. Internal -packages own candidate inspection, Git endpoint/ref operations, publication -reconciliation, cross-builds, subprocess execution, and Gitea transport/delivery. -Source publication and asynchronous delivery have separate outcomes. Page-only -delivery and the three initial binary targets are implemented. The default -suite uses local collaborators and is independent of consuming checkouts. - -This structure substantially matches the decision. R5 identifies implementation -mechanics still placed in the public package. The more consequential gaps are -source/artifact binding and accurate recovery state, rather than exposed type -ownership or runtime dependency weight. - -## Findings - -### R1 — High: Delivery accepts binaries built from uncommitted source - -Status: Resolved. - -Category: Correctness and divergence from tagged-source delivery. - -**Evidence:** [The builder](../../internal/build/build.go) records `HEAD` in -`gitCommit` but compiles the current worktree without establishing that it is -that committed source. [Delivery](../../internal/delivery/delivery.go) checks -checkout cleanliness and tag equality at delivery time, then accepts matching -commit metadata and artifact hashes. The [receipt adapter](../../cmd/releasekit/internal/cli/receipt.go) -adds hashes and build settings, but no evidence of source cleanliness during -compilation. - -A temporary application was committed and tagged, changed to print -`UNCOMMITTED`, and built successfully. Its result recorded the original tagged -commit. After restoring the original clean source, `Deliver` accepted the -result and uploaded the uncommitted binary and manifest with state `complete`. -No caller forged metadata or edited a receipt. - -**Required remediation:** Bind delivery-eligible build results and receipts to -the committed source actually compiled. Observe the relevant source state -before and after compilation, or build the committed source in a controlled -checkout. Verify eligibility when consuming a result or receipt. Keep ordinary -local build behavior explicit: this finding does not authorize a universal -clean-`main` restriction, an attestation system, or a concurrency-proof source -snapshot guarantee. Delivery still accepts detached historical tagged source. - -**Focused verification:** An ordinary build from modified source must not -become eligible for tagged delivery merely by cleaning the worktree afterward. -Cover source changes during a build and unchanged clean tagged builds through -the supported API and CLI receipt path. - -**Resolution:** Build results and private receipts now carry `SourceVerified`, -set only after completed builds observe clean source and unchanged HEAD. Local -dirty builds remain supported; binary delivery rejects their results and -receipts even after checkout cleanup. API tests cover clean, initially dirty, -changed-during-build source, and HEAD advancement; a CLI regression covers -receipt delivery after -cleanup. The offline suite and public boundary checks pass. - -### R2 — High: Some successful page writes are reported as not attempted - -Status: Resolved. - -Category: Failure handling and recovery-state correctness. - -**Evidence:** [EnsureRelease](../../internal/gitea/release.go), at the -`postErr == nil` branch around line 152, returns `acceptCreated` directly. -Semantic verification failures therefore bypass the reconciliation used for -JSON decoding or transport failures. [Delivery](../../internal/delivery/delivery.go) -then calls `stateForError(err, false)` and reports `not_attempted`. - -A fixture stored the requested page, returned HTTP 201 with a different title, -and exposed the correct page on subsequent GET. Delivery returned -`not_attempted` and `malformed_response` after one POST and only the initial -page lookup. It did not perform the selected reconciliation lookup, even though -the page existed. A reconciled successful create also loses write history when -`acceptExisting` returns `Created: false`, affecting subsequent error reporting. - -**Required remediation:** Route both syntactic and semantic create-response -failures through the one-lookup recovery path. Preserve sufficient write and -confirmed-page progress to classify later failures accurately. A confirmed -page match resolves delivery of that page; unresolved write outcomes remain -unknown. Retain the selected bounded reconciliation and immutable-content rules. - -**Focused verification:** Cover HTTP 201 with an inconsistent decoded response, -its matching and conflicting follow-up lookups, and a recovered create followed -by asset-inspection failure. Assert both request counts and returned state. - -**Resolution:** Semantic create-response failures now use one reconciliation -lookup. Recovered page results retain create-request history, preserving partial -progress on later asset-inspection failure. Local HTTP tests cover matching, -conflicting, and unavailable lookups; a CLI fixture verifies recovered creation -followed by failed asset inspection. Both affected suites pass. - -### R3 — Medium: Read-only asset failures are classified as unknown writes - -Status: Resolved. - -Category: Divergence from the selected outcome contract. - -**Evidence:** [UploadMissing](../../internal/gitea/upload.go), around line 102, -sets `DeliveryUnknown` when preflight contains an unverifiable attachment. -This occurs before any upload. [The CLI](../../cmd/releasekit/main.go) maps that -state to exit 3, documented as an unresolved remote mutation. - -With an existing matching page and an attachment download returning HTTP 503, -a local reproduction returned `unknown` with zero POST requests. Uncertainty -about existing content was promoted into uncertainty about a write that never -occurred. - -**Required remediation:** Keep unverifiable-content facts separate from -uncertain mutation outcomes. Report a known inspection failure when no write -was attempted; preserve partial page progress if this invocation already -created a page. Reserve unknown-write state and exit 3 for unresolved writes, -as selected in the plan. Adjust tests and documentation consistently. - -**Focused verification:** An unreadable existing attachment on an otherwise -read-only invocation must not return unknown-write state or exit 3. A genuinely -ambiguous upload must continue to do so. - -**Resolution:** Unverifiable preflight assets now return an inspection failure -with `not_attempted`, retaining partial page progress when creation preceded -the read failure. CLI tests cover existing and newly created pages, no asset -writes, and exit 1. Existing ambiguous-upload regressions still verify unknown -write outcomes. Both affected suites pass. - -### R4 — Medium: Local artifact regeneration is prohibited - -Status: Resolved. - -Category: Inadvertently strengthened prohibition. - -**Evidence:** [Build](../../internal/build/build.go), around line 114, refuses -any existing selected artifact filename, including its own prior output. A -second identical successful-build request to the same directory fails with -`already exists; preserving caller-owned file`. The -[build guide](../consumers/build.md) and [CLI contract](../cli.md) turn this -implementation choice into a stated restriction. - -The plan selects regeneration of owned local filenames while preserving -unrelated files. Published remote content remains immutable; that rule does -not prohibit rebuilding local output. This refusal also obstructs recovery -from a partial local build without manual deletion. - -**Required remediation:** Regenerate the selected tool-owned local outputs and -preserve unrelated files. Keep receipt validity consistent with complete build -and smoke success when outputs are regenerated. Update tests and the current -documents to remove the blanket existing-output prohibition. Use ordinary -filesystem operations without adding broad directory cleanup or durability -machinery. - -**Focused verification:** Repeating a build in its output directory succeeds; -a changed local build can regenerate its owned names; unrelated files survive; -a partial rebuild does not authorize incomplete assets through a stale receipt. - -**Resolution:** Builds regenerate selected local artifact names and preserve -unrelated output files. The CLI invalidates prior receipts once a rebuild has -reached its output directory, including failed rebuilds. API regressions cover -repeated and changed-source builds; CLI coverage proves a failed smoke check -removes the previous receipt. Affected suites pass. - -### R5 — Medium: The root facade still owns release mechanics - -Status: Resolved. - -Category: Architectural ownership gap and maintainability. - -**Evidence:** [candidate_build.go](../../internal/build/candidate.go) implements temporary -storage allocation, containment checking, cleanup, and candidate-build -coordination in the public package. [delivery_assets.go](../../internal/delivery/assets.go) -implements artifact inventory validation, file opening/stat/hash checks, -filename derivation, and manifest assembly there. These are substantial -implementation responsibilities beyond forwarding and type conversion. - -No internal type leak was found. The gap is the placement of mechanics that -ADR 0001 and the architecture policy assign behind the internal boundary. - -**Required remediation:** Move these responsibilities into cohesive internal -implementation, leaving the root package to own supported declarations, -explicit conversion, callback adaptation, forwarding, and error identity. -Choose package placement around existing responsibilities; add no public -assembly API or generic framework. - -**Focused verification:** Existing external-package behavior and boundary -checks remain valid after the move. Confirm filesystem and artifact algorithms -are owned internally without introducing inward imports of public facades. - -**Resolution:** Candidate-build coordination now belongs to `internal/build`; -artifact inventory, hashing, and manifest assembly belong to `internal/delivery`. -The root facade performs conversions and forwarding only. Existing artifact -tests moved with their implementation; external API and CLI tests, the complete -offline suite, and compiled-export/import checks pass. - -### R6 — Medium: Builds require a writable parent of the repository - -Status: Resolved. - -Category: Inadvertently strengthened filesystem prerequisite. - -**Evidence:** [Candidate builds](../../internal/build/candidate.go), around line 21, -and [CLI delivery builds](../../cmd/releasekit/main.go), around line 194, -allocate temporary storage with `os.MkdirTemp(filepath.Dir(repositoryDir), ...)`. -The requirement is disposable output outside the worktree, not sibling output. - -A clean candidate in a writable repository under a read-only parent failed at -candidate temporary-directory creation with `permission denied`, despite an -available writable system temporary directory. - -**Required remediation:** Allocate ordinary temporary build storage outside the -worktree without requiring write access to its parent. Share the mechanism -where appropriate. Preserve cleanup of tool-owned temporary paths and avoid -adding broad output-directory restrictions. - -**Focused verification:** Candidate and temporary delivery builds work with a -read-only repository parent and a usable system temporary directory. Generated -candidate output still leaves the worktree clean. - -**Resolution:** Candidate and CLI delivery builds use shared system temporary -storage allocated by `internal/tempdir`, with worktree containment checks and -caller-owned cleanup. Regressions execute both operations with read-only -repository parents and confirm clean worktrees. Additional helper regressions -cover relative system temporary paths and cleanup after rejecting in-worktree -storage. Affected suites pass. - -### R7 — Medium: Attachment origin restrictions exceed credential isolation - -Status: Resolved. - -Category: Inadvertently strengthened prohibition. - -**Evidence:** [downloadHash](../../internal/gitea/assets.go), around lines 164 -and 188, rejects cross-origin attachment URLs and redirects before making a -request. The [integration guide](../integrations/gitea.md) and tests state this -as a prohibition. A matching asset hosted by a second local server was marked -unverifiable; that server received zero download requests. - -The selected requirement keeps authorization on the configured Gitea origin. -It does not prohibit downloading an attachment elsewhere without that token. -The implementation adds a deployment restriction for external asset hosting. - -**Required remediation:** Support content verification across attachment URLs -and redirects while sending the Gitea token only to the configured origin. -Keep credential supply explicit and retain digest comparison. Remove the -stronger request-origin ban from tests and documentation; introduce no new -network-policy framework. - -**Focused verification:** Matching cross-origin bytes can be verified and -conflicting bytes rejected. Direct and redirected external requests never -carry the Gitea token; same-origin authenticated downloads continue to work. - -**Resolution:** Attachment URLs and redirects may cross origins; the client -sets the Gitea token only on requests to its configured origin. HTTP tests -verify direct and redirected external matches, conflicting external bytes, -absence of authorization on external requests, and continued same-origin -authentication. The Gitea suite passes. - -### R8 — Medium: The release wrapper collapses documented exit codes - -Status: Resolved. - -Category: Executable integration and documentation correctness. - -**Evidence:** [scripts/release](../../scripts/release), line 9, executes -`go run ./cmd/releasekit publish`. The Go driver exits 1 when its child exits -2 or 3. [The runbook](../release.md) attributes the native CLI's distinct -statuses to that wrapper. - -Both `go run ./cmd/releasekit check invalid` and `./scripts/release invalid` -returned shell status 1; the native CLI classifies invalid versions as 2. -The same driver behavior loses the unknown-publication status 3. - -**Required remediation:** Keep source bootstrap, but build and invoke the native -executable with the prepared local toolchain so the maintainer entry point -preserves its status. Keep generated tool output ignored or outside the -worktree. Clarify the distinction for retained `go run` examples, and make -runbook status claims match the actual entry point. This adds no publication, -distribution, or external preparation gate. - -**Focused verification:** The real wrapper preserves invalid-input status 2 and -unknown-publication status 3, as well as ordinary success and known failure. -Use local fixtures rather than a real publication endpoint. - -**Resolution:** The source wrapper builds its native executable into ignored -`.releasekit/bin` and invokes it directly. Documentation distinguishes native -exit codes from `go run` driver behavior. Local-repository tests execute the -actual wrapper and verify success 0, rejected publication 1, invalid input 2, -and unresolved publication 3. The focused wrapper test passes. - -### R9 — High: Manual recovery inspects the fetch endpoint - -Status: Resolved. - -Category: Release recovery correctness and documentation gap. - -**Evidence:** [The runbook](../release.md), around line 82, prescribes -`git ls-remote --refs origin refs/tags/` and permits local-tag removal -when that query returns absence. This query uses the normal fetch URL, whereas -the selected publisher deliberately supports a separate push URL. - -A local `origin` with different bare fetch and push repositories returned no -tag through the documented query after that tag was successfully published to -the push repository. The actual publication endpoint still contained the tag. -The CLI's failure summary currently omits the captured endpoint present in -`PublicationResult.Endpoint`. - -**Required remediation:** Make recovery inspect the exact captured publication -endpoint and intended tag object. Provide the needed endpoint information in -CLI recovery output and accurate copyable instructions. Do not infer that a -published version or local tag is safe to remove from absence at the fetch -repository. Preserve the existing rule that unresolved publication retains the -local tag. - -**Focused verification:** Exercise the documented recovery path with separate -fetch/push repositories and confirm that a published tag is recognized. Include -endpoint changes after an uncertain push when verifying retained recovery facts. - -**Resolution:** Failed publication output includes the captured endpoint. The -runbook checks URL resolution and queries that exact endpoint, retaining tags -on failed or unresolved checks. Local wrapper fixtures use separate fetch and -push repositories; a lost acknowledgment changes the configured push URL, and -recovery still finds the intended object at the captured endpoint while the -fetch endpoint reports absence. The guarded runbook commands are exercised -verbatim, including refusing a query after URL rewriting changes the endpoint. -Focused publication/wrapper tests pass. - -### R10 — Medium: The boundary checker bans valid command-internal composition - -Status: Resolved. - -Category: Inadvertently strengthened architectural prohibition. - -**Evidence:** [checkImportDirections](../../internal/apicheck/main.go), around -line 115, applies its blanket rejection of every `cmd/` import to command-owned -internal packages too. A temporary overlay fixture supplied a dependency from -`cmd/releasekit/internal/cli/parser` to -`cmd/releasekit/internal/cli/settings`; the checker rejected it as importing a -public or command package. - -Both sides are internal helpers owned by the same executable. This composition -respects the agreed separation of command parsing from facade calls. The -checker adds a prohibition that would constrain ordinary internal refactoring. - -**Required remediation:** Distinguish library internal packages, executable -controllers, and command-owned internal helpers. Keep library dependencies -inward and keep facade calls in the controller, while permitting coherent -command-internal collaborators to use their own internal contracts. Avoid -turning current package inventory into a fixed future architecture. - -**Focused verification:** A command-internal helper dependency passes. Library -internal imports of command code and internal-helper imports of public facades -remain rejected. - -**Resolution:** The import checker identifies each executable’s internal helper -subtree and permits collaboration inside it. Library-to-command imports, -helper-to-controller imports, and internal-to-facade imports remain rejected. -Positive and negative dependency fixtures and the actual compiled repository -boundary checks pass. - -## Completion verification - -The final uncached offline suite passes with `go test -count=1 ./...`, using -`GOWORK=off`, `GOPROXY=off`, `GONOPROXY=none`, `GOSUMDB=off`, and -`GOTOOLCHAIN=local`. `go run ./internal/apicheck` passes against the completed -facades and dependency graph. All ten findings have resolution notes and -focused behavioral evidence. Changed documentation's local links and fragments -and prose whitespace validate. Each implementation unit and follow-up fix was -committed separately with a plain English message; every commit is nonempty. - -The current root facade contains declarations, explicit conversions, callback -adaptation, and forwarding. Filesystem and artifact mechanics are internal; -`buildinfo` retains its lightweight runtime boundary. The new source-eligibility -fact records ordinary pre/post-build observations and adds no attestation or -concurrency-proof snapshot guarantee. Hosted content remains immutable, and -source publication remains independent of asynchronous delivery. - -All verification used local Git and HTTP collaborators. No real source release, -hosted delivery, consumer migration, or live CI activation was performed. - -## Remediation boundaries - -The completed work repairs the selected behavior and ownership boundaries, -with focused regression checks for the reproduced defects. It preserves the -two facades, selected publication -standard, immutable hosted contents, lightweight runtime dependency graph, -source-only hosted pages, and separate publication/delivery status. - -The findings require no consumer migration, intermediate release, live service -probe, or new human approval gate. After remediation, the maintainer can choose -the broader testing, adoption, and deployment steps. diff --git a/ideas.md b/ideas.md index 44e25ee..8140a11 100644 --- a/ideas.md +++ b/ideas.md @@ -1,4 +1,4 @@ # ReleaseKit ideas -The [ReleaseKit proposal](docs/roadmap/releasekit.md) owns the shared release -process ideas, proposed capabilities, and implementation plan. +The [product roadmap](docs/roadmap/releasekit.md) records shared release-process +adoption goals and remaining release and deployment work.