# ReleaseKit v0.2.0 implementation plan Status: Agreed stages for the remaining v0.2.0 work. This plan replaces the completed foundation sequence. It implements the target state in [v0.2.0.md](v0.2.0.md), using the shared design in [model.md](model.md), [ADR 0003](../adr/0003-declarative-validation.md), and [ADR 0004](../adr/0004-module-selected-tooling.md). A Luna coding agent should execute one numbered stage per prompt, in order. ## Current baseline and completion scope At `3974a46`, the foundation and all six [remediation findings](remediation.md) are complete. `Check` and `Publish` share candidate-request conversion and validation. `internal/validation` runs the default offline suite and owns diagnostics and candidate-tree access. Committed-file readers are offline; destination resolution handles symlinks, parent traversal, cancellation, and absolute in-checkout paths. The root error types and CLI presentation preserve findings and cause context. `buildinfo` retains its independent runtime dependency graph. The shared validation specification and profile settings are implemented incrementally with each capability; remaining selections are not yet implemented. The consumer CI template still selects an independent tool version. This sequence completes every remaining release-roadmap capability and Audita's CI migration. It ends with local verification and committed changes. Architecture review, hosted deployment, release tagging, and decisions about further testing follow this implementation. | Release-roadmap item | Implementation stages | | --- | --- | | 1. Shared validation API/profile model | 1–3, 5–11, 15 | | 2. Module-selected CI tool and Audita migration | 12–14 | | 3. One suite with race selection | 1 | | 4. Separate full vet | 2 | | 5. Package compilation | 3 | | 6. Expected publication endpoint | 4 | | 7. Go formatting | 5 | | 8. Markdown links and optional boundary | 9–11 | | 9. Independent distribution rules | 6–7 | | 10. Individual file size | 8 | ## Instructions for every stage - Start with [development.md](../development.md) and applicable policies. Locate current symbols with the codebase graph and inspect the worktree. The named paths below describe the current baseline. - Introduce each public and profile setting with its working capability, as agreed. Update its GoDoc, configuration reference, consumer guidance, and relevant CLI/internal documentation in that same stage. - Use ordinary internal structs/functions and explicit facade conversions. Keep product assertions in `AdditionalChecks` and profile `checks`. - Select tests for the stage's actual risks under the [testing policy](../policy/testing.md). Use local Git repositories, Go packages, controlled command doubles, and HTTP fixtures. Default tests remain offline and independent of real credentials or sibling checkouts. - Verification lists describe required evidence, including existing tests. Give each behavior a test owner: parser/checker tests cover syntax and rules; candidate-tree and Git tests cover file access and resolution; conversion tests cover each API/profile selection; shared orchestration tests cover ordering, failure stopping, cancellation, and callback execution. Use representative integration cases to verify these boundaries work together. Add coverage where the change introduces a risk or leaves an evidence gap. - Prepare newly selected development dependencies before offline validation. Apply the [OSS policy](../policy/oss.md) when adding dependencies or adapting third-party material, including any required attribution and license texts. - Verify the focused outcome, stage its relevant changes, review the diff, and create a nonempty commit with a short plain English message. Preserve unrelated work, report the stage's outcome and verification, and stop until the next stage is requested. These stages require local work and automated checks; consumer changes in Stage 14 are committed in that repository. ## Design carried through the stages ### Public and profile declarations The completed specification is facade-owned: ```go type ValidationSpec struct { Go GoValidationSpec GoFormat bool Markdown *MarkdownValidationSpec ModuleDistribution ModuleDistributionValidationSpec FileSize *FileSizeValidationSpec } type GoValidationSpec struct { Race bool FullVet bool CompileTargets []Target } type MarkdownValidationSpec struct { EnforceCheckoutBoundary bool } type ModuleDistributionValidationSpec struct { WorkspaceFiles bool LocalReplacements bool } type FileSizeValidationSpec struct { LimitBytes *int64 Exclusions []string } ``` Add `Validation ValidationSpec` and `ExpectedPushURL string` to `ReleaseRequest`. `Target` is the existing root-facade operating-system/architecture pair. Each stage adds only the fields it makes operational. The CLI owns corresponding JSON structs and converts them in `cmd/releasekit`; internal production packages use their own contracts. | Go selection | Profile selection | Omitted/zero behavior | | --- | --- | --- | | `Go.Race` | `validation.go.race` | Ordinary native test suite | | `Go.FullVet` | `validation.go.full_vet` | Existing test-time vet | | `Go.CompileTargets` | `validation.go.compile_targets` | No package-compilation pass | | `GoFormat` | `validation.go_format` | No formatting check | | `Markdown` | `validation.markdown` | Nil/omitted/null disables the check; `{}` enables it | | `Markdown.EnforceCheckoutBoundary` | `validation.markdown.enforce_checkout_boundary` | Outside-checkout links reported as out of scope | | `ModuleDistribution.WorkspaceFiles` | `validation.module_distribution.workspace_files` | Rule disabled | | `ModuleDistribution.LocalReplacements` | `validation.module_distribution.local_replacements` | Rule disabled | | `FileSize` | `validation.file_size` | Nil/omitted/null disables the check; `{}` enables it | | `FileSize.LimitBytes` | `validation.file_size.limit_bytes` | Nil/omitted/null selects 1,000,000 bytes when enabled | | `FileSize.Exclusions` | `validation.file_size.exclusions` | No exclusions | | `ExpectedPushURL` | `expected_push_url` | Empty/omitted disables the publication expectation | Profile compilation targets use `GOOS/GOARCH` strings. Require a complete pair because a partial target would otherwise silently select different compilation. Use the existing Go target/environment mechanisms; let the selected Go toolchain report unsupported targets. An artifact naming constraint does not determine package-compilation compatibility. Byte limits are integer counts; zero is an explicit zero-byte limit, and negative counts are invalid. Exclusions are literal repository-relative file or directory paths; directory selections include committed descendants. Match path boundaries so excluding `assets` leaves `assets-other` selected. Ordinary relative path normalization is sufficient. An unmatched exclusion has no effect. Metacharacters remain literal Git path characters. ### Execution and ownership The shared procedure is one native test suite, selected full vet, selected package-compilation targets, and selected file checks, followed by product checks and existing artifact builds/rechecks. File-check ordering is an internal procedure: formatting, workspace files, local replacements, file size, then Markdown. Stop after a failed check. A checker may return multiple findings; this plan does not require collecting failures from every selected check. Resolve the Go environment once per validation operation and reuse it. Native race/vet work preserves the existing effective cgo/C-tool configuration. Static package compilation uses `CGO_ENABLED=0`. The existing offline module/toolchain controls remain owned by `internal/gotool`. Pass settings through the root `candidateRequest`, `internal/candidate.Request`, `internal/publish.Request`, and `validation.Request`. Both operations and their CLI forms use the same decisions. Keep expected URL comparison in publication preflight. Existing capture/rechecks, endpoint guards, recovery, publication completion, and delivery outcomes retain their meaning. Reuse the existing internal failures and facade conversion. Add stable identities `go-vet`, `package-compile`, `go-format`, `workspace-files`, `local-replacements`, `file-size`, and `markdown-links` as implemented. Supply paths, locations, targets, directives, and measurements as applicable. Preserve causes and cancellation through `errors.Is`/`errors.As`. CLI failures use existing exit classifications and complete contextual presentation. File checks share one candidate inventory per validation operation and load blobs as needed. Inventory includes tracked vendor files and nested modules. Regular source blobs feed formatting and Markdown parsing. Workspace-file detection includes named symlink blobs; module parsing follows committed symlinks to candidate-contained regular declarations. Unavailable selected input produces an inspection error. File size measures regular and symlink blobs. Gitlinks have no parent-tree blob size, and their contents remain outside the inspected tree. ### Dependencies and Markdown convention Use standard `go/format` for Go formatting. Its convention follows the Go standard library used to build ReleaseKit. Use `golang.org/x/mod/modfile` at `golang.org/x/mod v0.40.0` for complete module-declaration parsing. Use `github.com/yuin/goldmark/v2 v2.1.6` internally for Markdown AST parsing and source positions. Both selected module manifests support the existing Go 1.25 baseline; implementation should record their exact source revisions and notices under the OSS policy. References: [modfile](https://pkg.go.dev/golang.org/x/mod/modfile) and [Goldmark](https://github.com/yuin/goldmark/tree/v2.1.6). PromptKit's current script supplies the starting heading/link examples. Preserve its basic anchor transformation: lowercase heading text, retain Unicode letters and numbers, underscore, hyphen, and spaces, then replace spaces with hyphens. Use visible heading text from the Markdown AST, including inline code text and excluding HTML tags/formatting delimiters. Support ATX and Setext headings. For repeated headings, append increasing numeric suffixes starting at `-1`, selecting an unused identifier when a generated suffix collides with another heading. Document these refinements to the starting script's behavior. Recognize inline links, images, and full/collapsed/shortcut reference links through the parser. Code blocks and inline code supply examples rather than link nodes. Raw HTML destinations remain outside this Markdown-link capability. Undefined references rendered as ordinary text by the parser are not a new Markdown lint rule. Decode Markdown escapes/entities through the parser and percent escapes once when resolving URI path/fragment components. Compare decoded fragments in lowercase to preserve PromptKit's starting convention. Ignore URI query components for file existence. Empty paths target the source document; an empty fragment selects its top. Schemed and protocol-relative URIs receive no availability request. Fragment checking applies to regular Markdown destinations; other existing files/directories receive existence checking. Use committed destination resolution and cached parsed documents/anchors. Missing destinations, unresolved cycles, and missing supported anchors fail the selected Markdown check. Actual outside-checkout destinations are reported as out of scope by default and fail with boundary enforcement. Submodule-content observations remain reported as out of scope under either setting: the boundary option concerns checkout escape and does not establish a submodule prohibition. Write nonfailure observations to the supplied output writer; a nil writer selects ordinary quiet library use. Diagnostics identify the source use site, location, and destination. Document source columns as one-based byte columns. ### CI tool bootstrap Build using temporary copies of the released application's `go.mod` and `go.sum`, with Go's alternate `-modfile` and normal module preparation in those copies. Confirm that ReleaseKit is already selected before building its command. This preserves the application's version declaration and require/replace semantics while allowing missing tool-only indirect requirements/checksums to be prepared without dirtying immutable tagged source. It supports consumers whose application imports only lightweight `buildinfo`. Stages 12–14 implement this agreed approach. ## Stage 1: Introduce the specification with race selection **Completion:** Complete. `ReleaseRequest.Validation.Go.Race` and profile `validation.go.race` select `-race` for the single native Go suite. Both candidate operations share the selection, and race failures retain the `go-test` identity without falling back to an ordinary suite. **Outcome:** The first public/profile selection changes the one existing suite. 1. Add `ReleaseRequest.Validation`, `ValidationSpec.Go`, and `GoValidationSpec.Race`, plus equivalent CLI-owned JSON settings. Add explicit conversions through both candidate and publication request paths. 2. Build the base invocation in `internal/validation`: preserve `go test -mod=readonly -count=1 ./...`, adding `-race` when selected. Reuse the native Go environment and report tool/prerequisite failures as `go-test`. 3. Preserve additional-check and build ordering. Update exact API/profile references and add a minimal consumer example for the selection. **Verification:** Default and selected invocations, exactly one suite, API/profile selection equivalence, both operations, unavailable race prerequisites with no silent fallback, preserved causes/cancellation, and failure before product checks/builds/tag creation. Use a small real race-enabled fixture on supported hosts and a controlled Go command for portable prerequisite-failure coverage. ## Stage 2: Coordinate a separate full vet pass **Completion:** Complete. `ReleaseRequest.Validation.Go.FullVet` and profile `validation.go.full_vet` disable test-time vet for the one native test suite and run native `go vet -mod=readonly ./...` afterward. Vet failures retain the `go-vet` identity, and the selection is shared by the API and profile paths. **Outcome:** Full vet replaces test-time vet overlap through one declaration. 1. Add `Go.FullVet` and `validation.go.full_vet` through the same conversion path. 2. When enabled, add `-vet=off` to the one test invocation and run native `go vet -mod=readonly ./...` afterward using the same tool/environment. 3. Attribute vet failures to `go-vet` and update canonical usage guidance. **Verification:** Ordinary, race-only, vet-only, and combined selections; one suite; vet after successful tests; suppression of test-time vet only when selected; failure/cancellation stopping; default behavior and API/profile parity. Protect the selected command relationship without freezing incidental flag order. ## Stage 3: Compile packages for selected targets **Completion:** Complete. `Go.CompileTargets` and profile `validation.go.compile_targets` select static package compilation after tests and vet. Failures use `package-compile` and include the selected target; artifact building remains separate. **Outcome:** Source compatibility checks work independently of artifacts. 1. Add `Go.CompileTargets` and string-array profile targets. Convert to internal Go targets and validate complete pairs consistently for API and profile use. 2. After test/vet, run `go build -mod=readonly -o ./...` in static mode for each selected target. The Go build null-output mode suppresses executable output, including a module with a single main package. 3. Report failures as `package-compile`, including the selected target. Keep output names, linker version injection, smoke tests, receipts, and manifests in artifact building. Document compilation versus target execution. **Verification:** Linux amd64/arm64, a supported additional Go pair, source-only library, single-main and multiple-main modules (including repeated executable basenames), target failure, unchanged candidate files, `CGO_ENABLED=0`, preserved ordering, and page-only delivery with compilation selected but no build targets. Reuse the existing Go environment tests for controls already protected there. ## Stage 4: Compare the optional expected push URL **Completion:** Complete. `ReleaseRequest.ExpectedPushURL` and profile `expected_push_url` require an exact match with Git's resolved effective push URL before validation. Mismatches return `ErrUnexpectedPushURL` with expected and resolved values; `Check` ignores the publication-only expectation. **Outcome:** Publication rejects a different effective destination before validation. 1. Add `ExpectedPushURL` and `expected_push_url`, with an empty value selecting existing behavior. Carry it only into the publication request. 2. Immediately after resolving/capturing `endpoint.PushURL`, compare exact strings. Report expected and resolved values through a publication preflight error. Add `ErrUnexpectedPushURL` as a public sentinel using the existing shared-error ownership pattern so callers can use `errors.Is`. 3. Keep later endpoint rechecks and reconciliation intact. Update GoDoc, publication guidance, and the profile reference. **Verification:** Omitted/matching/mismatching values, Git `insteadOf` resolution, separate fetch/push URLs, exact spelling differences, mismatch before Go/callbacks or tag creation, and a local-only `Check` that ignores the publication expectation. Existing endpoint-change and uncertain-push tests keep their ownership. ## Stage 5: Check committed Go formatting **Completion:** Complete. `ValidationSpec.GoFormat` and profile `validation.go_format` run `go/format` on regular Go blobs from the captured commit. Findings identify unformatted paths; parser and inspection failures retain their causes, and the check leaves repository contents unchanged. **Outcome:** A declaration replaces tracked-file formatting loops. 1. Add `GoFormat` and `validation.go_format` with working executor integration. 2. Load the shared captured inventory and apply `format.Source` to regular `.go` blobs. Compare original and formatted bytes, preserving repository contents. 3. Return `go-format` findings for affected paths and preserve parser/inspection causes. Update usage and formatting-convention documentation. **Verification:** Formatted and unformatted files, parse errors, vendor/nested source, unusual filenames, committed versus worktree bytes, disabled/default behavior, API/profile parity, and failure before later product/build work. ## Stage 6: Select committed workspace-file inspection **Completion:** Complete. `Validation.ModuleDistribution.WorkspaceFiles` and `validation.module_distribution.workspace_files` report committed blob entries named `go.work` or `go.work.sum`, including nested paths and symlinks. The rule inspects the captured candidate independently of `GOWORK` and leaves the Go workspace environment and vendor behavior unchanged. **Outcome:** One distribution rule works independently of the Go environment. 1. Add `ModuleDistributionValidationSpec.WorkspaceFiles` and the matching JSON group/field. The remaining rule is added in Stage 7. 2. Inspect committed blob entries named `go.work` or `go.work.sum`, including nested and symlink entries. Report paths using `workspace-files`. 3. Keep testing's existing workspace setting and consumer vendor choices in their current owners. Document the distinction between environment and distribution. **Verification:** Either workspace filename, nested paths, symlink names, committed files with `GOWORK=off`, uncommitted files excluded from inspection, selection disabled, and shared API/profile execution. Use meaningful rule cases rather than retesting Git enumeration mechanics. ## Stage 7: Select filesystem replacement inspection **Completion:** Complete. `Validation.ModuleDistribution.LocalReplacements` and `validation.module_distribution.local_replacements` parse committed `go.mod` declarations, including nested/vendor files and committed symlink declarations. Filesystem replacements report their declaration path, line, directive, and target as `local-replacements`; versioned replacements are permitted. Parse and inspection failures retain their causes, and this rule is independent of both workspace-file selection and `GOWORK`. **Outcome:** The second distribution rule parses actual module declarations. 1. Add `ModuleDistribution.LocalReplacements` and the equivalent profile field. Prepare `golang.org/x/mod v0.40.0`, module sums, and required OSS notices. 2. Parse committed `go.mod` files with `modfile.Parse`, including nested/vendor declarations. Resolve symlink declarations within the candidate; report an inspection error when their selected contents cannot be obtained locally. 3. Identify filesystem replacements by the parsed replacement's absent version; permit versioned replacements. Report path, directive/source location, and target through `local-replacements`, preserving parse/inspection causes. 4. Document independent distribution selections and their inspection scope. **Verification:** Single and block directives, comments, quoted paths, relative and absolute filesystem targets, versioned replacements, nested declarations, valid/broken symlinks, parse failure, and all independent boolean combinations. The rule applies to candidate contents even when testing disables workspace use. ## Stage 8: Inspect individual committed file sizes **Completion:** Complete. `Validation.FileSize` and `validation.file_size` enable a per-blob decimal-byte limit with a 1,000,000-byte default, strict greater-than comparison, and literal repository-relative file/directory exclusions. The check uses captured blob sizes, counts symlink link text, omits gitlinks, and reports one oversized file with its measurement. Nil disables the check, and historical or aggregate repository size is outside its scope. **Outcome:** Optional limits and intentional path exceptions are operational. 1. Add `FileSizeValidationSpec`, `ValidationSpec.FileSize`, and matching JSON fields according to the declaration table. Validate nonnegative byte limits. 2. Use shared blob sizes for regular files and symlink link-text blobs. Apply literal file/directory exclusions. On an oversized blob, return `file-size` with its path and existing `FileSizeMeasurement` fields; reporting one offending file per failure fits the current diagnostic model. 3. Document decimal bytes, strict greater-than comparison, exclusions, and current-candidate scope. Preserve default disabled behavior. **Verification:** Below/at/above limits, the exact 1,000,000-byte enabled default, zero/custom/negative limits, nil versus empty objects, directory/path boundaries, literal metacharacters, unmatched exclusions, small binaries, symlink sizes, and omitted submodule sizes. Historical and aggregate size do not become release gates. ## Stage 9: Implement internal Markdown parsing and anchors **Completion:** Complete. Goldmark now records parsed links, images, reference uses, use-site locations, and collision-free heading anchors behind an internal per-candidate document cache. Its behavior remains unselected until the later validation-integration stage. **Outcome:** A parser with source positions and documented anchor semantics is ready. 1. Add `github.com/yuin/goldmark/v2 v2.1.6`, prepared dependencies, and applicable OSS notices. Keep parser types inside internal implementation. 2. Parse links/images, reference uses, headings, and source positions into small internal records. Derive visible heading text and apply the convention above. 3. Cache parsed records/anchors per candidate document. Keep this stage internal; Stage 11 adds the public selection once complete checking works. 4. Compare fixtures with PromptKit's starting examples. Record intended refinements in the roadmap until the public behavior lands, avoiding a second regex parser. **Parser refinements:** PromptKit's starting script scans inline links, images, and ATX headings with regular expressions. The Goldmark parser also records resolved full, collapsed, and shortcut reference uses at each source use site. Heading anchors use decoded visible AST text, include inline code, exclude raw HTML tags, and support Setext headings. Parser-recognized CommonMark autolinks are recorded alongside inline and reference links. Repeated-heading suffixes skip identifiers already used by another heading. **Verification:** Inline/reference forms and images, escaped/parenthesized and angle-bracket destinations, optional titles, code fences/inline code, Unicode/entity headings, ATX/Setext headings, repeated headings and suffix collisions, and source use-site locations including repeated reference uses. Undefined references and HTML prose remain governed by parser interpretation. ## Stage 10: Implement internal destination and fragment checking **Completion:** Complete. The internal checker resolves committed destinations, checks supported fragments, preserves inspection errors, and reports distinct outside-checkout and submodule observations. Stage 11 exposes this checker through public and profile selections and the shared executor. **Outcome:** Committed Markdown navigation is checked with boundary observations. 1. Resolve parsed local URI components through `CandidateTree.ResolveDestination`. Apply escaping/query/fragment rules above and use actual resolved identities for target-document anchor lookup. 2. Check committed existence and supported heading fragments, recording source path/location/target. Produce `markdown-links` failures and distinct nonfailure observations for outside-checkout and submodule contents. 3. Implement optional checkout-boundary enforcement internally. Preserve the distinction between external URIs, checkout escapes, and uninspected submodules. 4. Reuse remediated symlink/cancellation/local-object behavior. Keep parsing, resolution, and rule evaluation in ordinary internal functions. **Resolution refinement:** URI query components do not participate in path checking. Compare fragments after one percent-decoding pass and lowercase them to preserve PromptKit's starting anchor matching. **Verification:** Valid/missing files and anchors, same-document/empty fragments, percent-escaped paths and fragments, query strings, directories and non-Markdown files, outside links with both settings, and submodule observations. Check how resolver results and inspection errors become Markdown findings, preserving causes and cancellation. Use representative committed-tree integration cases and verify unchanged candidate/worktree bytes. Existing candidate-tree and Git tests own detailed absolute-path, symlink-parent, cycle, neighboring-file, missing-object, and traversal-cancellation cases. ## Stage 11: Expose Markdown selection and complete validation integration **Completion:** Complete. `ValidationSpec.Markdown` and `validation.markdown` select the shared committed-link checker through both public operations and CLI profile commands. Omitted/null settings disable the check; an empty object enables it, and the boundary option maps explicitly. Warnings use the shared output writer, while Markdown failures stop product checks and builds. GoDoc, profile, consumer, CLI, and internal documentation now describe the operational behavior. **Outcome:** All agreed validation selections work through both public operations. 1. Add `MarkdownValidationSpec`, `ValidationSpec.Markdown`, and their JSON fields. Enable on a non-nil group/empty object and map the boundary boolean explicitly. 2. Wire the checker and nonfailure observations into the shared executor/output writer. Reuse existing facade/CLI diagnostic formatting and exit classification. 3. Document the newly operational Markdown selection in its canonical owners. Review earlier stages' GoDoc, configuration, check/publish guides, CLI reference, internal inventory, and examples for consistency across combined selections. 4. Use self-contained fixtures representing Audita defaults/artifacts, ConfigKit's race/vet/compilation, and PromptKit's shared settings plus example assertions. Document how consumers remove duplicate generic commands when adopting settings. **Verification:** Equivalent Go/profile declarations, nil/empty/null Markdown settings, warnings with successful results, boundary failures before product/build work, all-zero compatibility, representative combined selections, one suite and one additional-check callback. Run the compiled API/dependency check, including `buildinfo`'s standard-library/runtime-only dependency boundary. ## Stage 12: Build the CI tool from verified released module configuration **Completion:** Complete. The maintained tag workflow verifies and checks out the event tag before reading module files, then confirms the ReleaseKit module selection and builds its CLI with temporary alternate module metadata outside the source tree. The delivery command retains the event arguments and exit status, and the cleanup trap removes its module copies and executable. **Outcome:** The standard template has one tool-version declaration. 1. Revise `examples/woodpecker/tag-delivery.yml` into a compact bootstrap/delivery step. Use available Git to validate/fetch the explicit event tag, compare its peeled commit to the full provider object ID using existing case-insensitive object-ID semantics, check out that commit detached, and confirm HEAD and the existing clean tagged-source requirement. This ensures module files actually belong to the verified release before selecting the tool. Do this before reading/resolving the application module or executing Go. 2. Apply the agreed CI tool bootstrap approach: create a disposable directory outside the source checkout, copy its `go.mod` and existing `go.sum`, and use an alternate `-modfile` for tool resolution/build. Run from the verified source with `GOWORK=off` and `GOTOOLCHAIN=local`. 3. Confirm the ReleaseKit module is already selected by that module configuration using `go list -m`; then build its `cmd/releasekit` package without an `@version` suffix. Allow ordinary network-capable module preparation in the temporary metadata copies (`-mod=mod`). Respect selected require/replace relationships. 4. Invoke the resulting native executable's existing `ci-deliver` with the event repository, commit, and tag. Keep delivery credentials in the existing delivery step and use an exit cleanup trap for temporary metadata and executable files. 5. Remove the independent `RELEASEKIT_VERSION` workflow setting. Preserve current Go-image customization, destination/profile ownership, and delivery outcomes. Keep the bootstrap Git block small; the built tool retains its runtime guards. **Verification:** Execute maintained template commands with a local tag/module fixture and instrument Go/transport operations. Prove wrong tag/commit stops before module resolution/build, a dirty module cannot select a different tool, the verified checkout selects the tool, module metadata and source remain unchanged, and the executable/temporary files are cleaned up. Tool metadata preparation is separate from offline candidate checks. Include a representative case that verifies invocation of the selected executable with the event arguments and propagation of its exit status. Existing delivery tests own hosted behavior. ## Stage 13: Verify upgrades, retries, and bootstrap variants **Completion:** Complete. The tag workflow is exercised against a local module proxy with two tool versions, an older tagged configuration after the default branch upgrades, and a versioned replacement. Missing tool-only dependency checksums are prepared in temporary module metadata. The ReleaseKit source workflow verifies its tag before self-bootstrap and writes the executable outside the checkout. Delivery, configuration, and CLI guidance now distinguish tool bootstrap from application dependency preparation and describe immutable-source retries and installed-tool use. **Outcome:** Tool selection follows the triggering release across supported uses. 1. Extend Stage 12's bootstrap fixtures with a local module proxy for two tool versions and tagged consumer module configurations. Execute the maintained workflow body against both. Keep live infrastructure outside the default test suite. 2. Verify a retry of an older tag still selects that tag's module configuration when the default branch has upgraded. Include missing tool-only checksums and an existing versioned replacement to protect source-based resolution. 3. Align `releasekit-source-delivery.yml` with source verification before self bootstrap and temporary output. Preserve self-bootstrap from `./cmd/releasekit` and separately installed-tool guidance using the existing command. 4. Update delivery/configuration/CLI guidance and maintained templates together. Explain compatible Go environments, dependency preparation, immutable-source retries, and the distinct tool/app artifact preparation steps. **Verification:** Two dependency versions, older-source retries, self bootstrap, and separately installed tool, using the shared bootstrap fixtures. Existing delivery and publication tests retain ownership of source-only pages, binary delivery, destination handling, and publication states. Add integration coverage for any new interaction introduced by bootstrap changes. An application without a declared ReleaseKit dependency uses the installed-tool integration. ## Stage 14: Migrate Audita's local CI integration **Outcome:** Audita's local wrapper and CI select the same module-declared tool. 1. Read `../audita` orientation/policies and inspect its worktree before editing. Adapt `.woodpecker/release.yml` to the maintained module-based template, preserving its Go image, Gitea secret name, and release profile. 2. Retain its existing released ReleaseKit module selection for this migration; that version already supplies `ci-deliver`. Make any necessary adjustments to `scripts/release.sh` for the selected bootstrap metadata approach, preserving arguments and native executable exit behavior. Keep generated tool output outside the candidate source where needed. 3. Verify the consumer's actual wrapper/workflow using local tagged fixtures and prepared module caches. Confirm matching tool selection, preserved arguments and exit status, and unchanged source files. Review the diff for preservation of the release profile and binary targets. Existing consumer and ReleaseKit tests retain ownership of source validation and hosted delivery behavior. 4. Commit the focused migration in Audita with a plain English message. Record its commit and local verification in this plan's implementation status. **Verification:** The actual adapted consumer declarations use one dependency version; local and CI bootstraps agree and retain existing caller arguments/status semantics. Keep integration fixtures self-contained in ReleaseKit's default suite. This migration uses an existing release and requires no intermediate publication or live Woodpecker/Gitea run to complete the stage. ## Stage 15: Audit the completed v0.2.0 implementation **Outcome:** The entire scoped feature set is implemented and locally verified. 1. Match every row in the roadmap/stage table to implemented settings, execution, diagnostics, current documentation, and focused behavioral evidence. Verify all-zero compatibility, independent distribution choices, one coordinated Go suite, source-only compilation/delivery, and selected endpoint preflight. 2. Review new code and tests for unintended defaults, restrictions, caps, or stronger guarantees. Preserve user choice and the existing facade boundaries. 3. Run `go test ./...` and `go run ./internal/apicheck`. Add further integration coverage only for a concrete remaining risk. Check documentation links, fragments, whitespace, dependency notices, and maintained examples. 4. Update statuses in this plan, the release roadmap, and the model roadmap to reflect actual completion, including the Audita migration evidence. Update canonical current-behavior owners as needed and remove stale prospective text. 5. Commit the completed unit, report each stage's outcome and remaining work, and finish with a clean workspace while preserving any unrelated user changes. The subsequent architecture review and release/testing decisions follow here. ## Open Questions None.