diff --git a/docs/internal/validation.md b/docs/internal/validation.md index 27a2ba2..1c0b881 100644 --- a/docs/internal/validation.md +++ b/docs/internal/validation.md @@ -117,9 +117,7 @@ for product behavior. ## Go command environment reuse The current executor uses the [shared Go command environment](gotool.md) for -its offline suite, vet pass, and selected-target package compilation. The -[implementation roadmap](../roadmap/implementation.md#execution-and-ownership) -records the shared ordering across validation and later file checks. +its offline suite, vet pass, and selected-target package compilation. Reuse `internal/gotool` for native and static environments and target handling. Keep toolchain and module-cache discovery in `gotool`; do not reproduce its @@ -140,7 +138,6 @@ symlink expansion detects cycles, and traversal honors cancellation. Absolute destinations and symlink targets within the repository directory map back to candidate-relative paths; existence still comes from committed entries. -The [implementation plan](../roadmap/implementation.md) records the completed -Markdown integration. The public selection is owned by the facade and profile; +The public selection is owned by the facade and profile; the internal checker uses the committed-file and destination-resolution primitives described here. diff --git a/docs/roadmap/feature-request-configkit.md b/docs/roadmap/feature-request-configkit.md deleted file mode 100644 index 8e56b83..0000000 --- a/docs/roadmap/feature-request-configkit.md +++ /dev/null @@ -1,67 +0,0 @@ -# Feature request from ConfigKit: adaptable release validation - -Status: Requested by a prospective downstream consumer; not yet adopted by -ReleaseKit. - -ConfigKit would like to adopt ReleaseKit's common source-release process and -retire most of its repository-owned release scripts and publication tests. It is -a source-only Go library. ConfigKit can follow ReleaseKit's existing convention -of publishing the candidate to `main` before running the tag-publication -command; it does not need binary artifacts or a different source-publication -sequence. - -## Select one base Go test invocation - -ReleaseKit's [candidate check](../consumers/check.md) currently runs its -standard `go test` suite before any configured additional checks. ConfigKit's -selected release validation includes a race-enabled run of its full test -suite, with a separate full vet pass. Expressing the race run as an additional -check would run the suite twice and retain avoidable consumer-specific release -wiring. - -Please provide a small public API and profile capability for a consumer to -select its **one base Go test invocation** for candidate validation. The -selection should replace the default invocation, rather than add a second test -run. Without a selection, ReleaseKit's current default remains useful. Both -`Check` and `Publish`, including their CLI forms, should use the selected -invocation consistently while ReleaseKit continues to own candidate capture, -validation order, result reporting, and publication. ConfigKit needs to select -a full-suite race run with test-time vet omitted because it selects a separate -full vet pass. ReleaseKit can choose the simplest public expression of that -choice; ConfigKit is not asking for a general-purpose release pipeline or -consumer-owned orchestration. - -## Evaluate shared release checks - -ConfigKit also uses a separate full `go vet` pass and compile checks for Linux -amd64 and arm64. Please assess whether these checks are useful enough across -ReleaseKit consumers to offer directly through its public API and profile, -either as defaults or as selected options where product support differs. - -In particular, a source-only library needs to verify that its packages compile -for selected targets without declaring executable artifacts or adding delivery -work. ReleaseKit could make that distinction available to consumers. The goal -is to keep these checks, when selected, within the same candidate validation -and publication flow without repeating work already done by the base test. -Whether race, vet, or cross-target compilation should be common defaults is a -ReleaseKit product decision; ConfigKit asks for an assessment, not a universal -new release gate. - -## Optional publication endpoint expectation - -ConfigKit currently identifies one expected authoritative Git destination. An -optional expected-endpoint setting in ReleaseKit's public API and profile could -let a consumer verify that the selected remote resolves to its declared -destination before publication. Please consider whether this is broadly useful -and simpler than retaining a small consumer-owned preflight check. Existing -ReleaseKit remote selection and endpoint handling should remain the common -publication model. - -## Adoption outcome - -A useful outcome would let ConfigKit declare its product identity, selected -validation, and any expected publication destination, then rely on ReleaseKit's -standard candidate check and tag-publication command. ConfigKit would retain -its compatibility decisions and release notes while removing duplicated release -mechanics. Source publication would still complete at the confirmed tag push; -CI and hosted delivery would remain separate from that completion point. diff --git a/docs/roadmap/feature-request-promptkit.md b/docs/roadmap/feature-request-promptkit.md deleted file mode 100644 index 444ee08..0000000 --- a/docs/roadmap/feature-request-promptkit.md +++ /dev/null @@ -1,182 +0,0 @@ -# Feature Request From PromptKit: Shared Release Validation - -Status: Requested by a prospective downstream consumer; not yet adopted by -ReleaseKit. - -Date: 2026-10-07. - -This request derives from PromptKit's -[ReleaseKit adoption assessment](https://gitea.maximumdirect.net/eric/promptkit/src/commit/7310ef34a44dae7288db7b281e2a6b7f2c56c4e9/docs/roadmap/releasekit.md), -which reviewed ReleaseKit `v0.1.0`. It describes downstream needs and leaves -public API design, shared defaults, and implementation choices to ReleaseKit. - -## Consumer Context And Goal - -PromptKit is a source-only Go library with concurrent LLM execution and -backend-capacity management. It would like to adopt ReleaseKit's common -source-publication process and reduce its own release infrastructure to -product settings and a few substantive project checks. Its existing release -scripts contain 209 lines, most of which implement validation rather than -publication. - -PromptKit accepts changes to its release process in exchange for a common -standard and lower maintenance. The opportunity is to share useful validation -capabilities, rather than preserve every existing shell command or local rule. -Its consumer-example assertions and compatibility decisions remain meaningful -project responsibilities. - -The four primary requests below concern reusable validation. Two additional -candidates are included for evaluation if their wider value justifies shared -support. PromptKit's choices about race testing, full vet, and credential -scanning remain under review; these requests describe useful capabilities -without making their acceptance a prerequisite for adoption. - -## Primary Requests - -### 1. Shared Go Formatting Validation - -Please make Go formatting validation available through ReleaseKit's public -validation API and release profile, so the shared candidate workflow can -report tracked Go source that needs formatting. - -PromptKit currently owns a shell check that identifies its tracked Go files -and verifies their formatting. The operation is common to Go repositories; -maintaining that mechanism independently adds little project-specific value. -A useful shared capability would inspect source, report the affected files, -and leave formatting changes to ordinary development. - -The benefit is consistent validation and diagnostics with less local script -maintenance. PromptKit can follow ReleaseKit's selected formatting convention -without requiring preservation of its current enumeration or command loop. - -### 2. Shared Offline Markdown-Link Validation - -Please make validation of local Markdown links available through the public -validation API and release profile. PromptKit needs checks for local file -destinations and heading fragments, with enough diagnostic context to locate -and correct a broken link. - -Documentation is part of PromptKit's consumer interface. Broken navigation -between its guides, formats, policies, and examples makes otherwise correct -documentation harder to use. Its current local Markdown checker is the -largest generic block in its release-validation script. - -Shared support would remove a locally maintained parser and standardize the -supported Markdown behavior across consumers. ReleaseKit can establish the -supported link and heading conventions; PromptKit does not require its exact -current parsing or anchor rules. Repository-specific choices about links to -material outside the checkout should remain distinguishable from generally -useful local-link validation. - -The desired operation is offline and reports problems without changing -documentation. External website availability is a separate concern and adds -no value to this request. - -### 3. Race Detection Within One Standard Test Run - -Please provide a supported public API and profile choice for race-enabled -execution of the standard full Go suite during candidate validation. - -PromptKit's concurrent execution and capacity management make race detection -useful: ordinary successful tests can miss unsafe shared-state access. Its -current release validation runs the full suite with the race detector. -ReleaseKit's current -[candidate workflow](../consumers/check.md) always runs the ordinary suite; -expressing a race run as an additional check would execute the complete suite -twice. - -The desired capability selects race-enabled execution for that one suite -run, while ReleaseKit continues to own the candidate workflow. The selection -should work consistently through the public API and CLI/profile forms of -candidate checking and publication. A consumer can select the ordinary suite -when that is sufficient. - -This overlaps with ConfigKit's -[base-test invocation request](feature-request-configkit.md#select-one-base-go-test-invocation). -PromptKit would benefit from the same shared capability; it does not need a -separate PromptKit-specific test mechanism. ReleaseKit can decide the smallest -appropriate public expression of the choice and whether race testing belongs -among its common defaults. - -### 4. Shared Full Go Vet Validation - -Please consider exposing full Go vet analysis as part of ReleaseKit's public -validation API and release profile, coordinated with the standard suite. - -PromptKit currently runs full vet separately. Ordinary Go test execution -includes only a subset of vet analyses, so replacing the current procedure -with the standard test run does not provide equivalent static analysis. The -additional analyses can detect defects that are not exercised by tests. - -PromptKit can temporarily retain a configured full-vet command. A shared -capability would let consumers express that validation choice directly and -let ReleaseKit coordinate the analysis with testing to avoid unnecessary -overlap. The desired outcome is full selected analysis and one complete -suite execution; PromptKit leaves the means of achieving that outcome to -ReleaseKit. - -This also overlaps with ConfigKit's -[shared-check request](feature-request-configkit.md#evaluate-shared-release-checks). -Full vet may be useful as a common default or as an explicit selection. -PromptKit is asking for a shared capability, not prescribing additional gates -for every ReleaseKit consumer. - -## Additional Candidates For Evaluation - -### 5. Optional Go Module Distribution Checks - -PromptKit's architecture keeps committed workspace files and local filesystem -module replacements out of its released source. These rules help a shared -library remain independent of neighboring checkouts. Disabling workspace -discovery during validation controls the test environment but does not check -the files being distributed. - -If other consumers have the same need, optional public validation capabilities -could check for committed workspace files and local filesystem replacements. -Consumers should be able to select the distribution rules relevant to them; -a versioned module replacement is different from a local filesystem -dependency, and Go applications may deliberately distribute workspace files. - -The potential benefit is reusable inspection and consistent diagnostics -without each library owning its own checks. PromptKit can also keep a small -local check if that is simpler than introducing shared support. This is a -lower-priority candidate, not a request for universal bans on workspaces, -replacement directives, or vendoring. - -### 6. Optional Recognizable-Credential Checks - -PromptKit's assessment recommends retiring its mandatory credential-pattern -scan, while retaining ordinary credential-aware change review. A viable -alternative is to keep a lightweight automated signal for recognizable -accidentally committed credential formats. - -If ReleaseKit finds broader consumer value in that alternative, please -consider an optional public validation capability for such checks. A useful -offering would make its detection scope clear and account for the possibility -of matching synthetic examples or fixtures. It would complement ordinary -review rather than imply comprehensive detection. - -Shared support could centralize maintenance of the selected detection behavior -and remove another local script fragment. PromptKit is not requesting a -general security-scanning subsystem, preservation of its current regex, or -a mandatory credential gate. This candidate warrants adoption only if its -additional protection justifies its maintenance and false-positive costs. - -## Desired Adoption Outcome - -The strongest opportunities are shared formatting and Markdown validation, -followed by useful race/vet choices within a single candidate-validation flow. -The module-distribution and credential candidates merit separate evaluation -because their policies and benefits vary between consumers. - -For accepted capabilities, availability through both the public Go API and -the maintained CLI/profile would let PromptKit select them without creating -its own release executable. PromptKit can retain its consumer-example -assertions as additional checks and use ReleaseKit's supported conventions -for shared validation and diagnostics. - -PromptKit would continue to prepare its release note and publish its candidate -to authoritative `main` before invoking source publication. Confirmed tag -publication completes the source release; CI and hosted delivery remain -separate. Those responsibilities already fit ReleaseKit's common workflow -and do not require new features for this request. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index 471e60e..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,656 +0,0 @@ -# ReleaseKit v0.2.0 implementation plan - -Status: Complete. Stages 1–15 are implemented and locally verified. - -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 baseline commit `3974a46`, the foundation and all six -[remediation findings](remediation.md) were complete. `Check` and `Publish` -shared 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 stages in this plan complete the remaining v0.2.0 validation selections, -module-selected CI bootstrap, and Audita migration. Audita's migration is -recorded in commit `17421bc`. The final local audit covers the full Go suite, -compiled API/dependency boundaries, maintained examples, documentation, and -dependency notices. 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 - -**Completion:** Complete. Audita commit `17421bc` makes both local and hosted -bootstraps resolve ReleaseKit v0.1.0 from the consumer's module configuration. -The existing Go image, `GITEA_RELEASE_TOKEN` secret, release profile, caller -arguments, and native tool status are preserved. The local wrapper uses -temporary alternate module metadata and cleans it up before executing the tool. -Audita's runbook now describes the module-selected workflow. - -**Verification:** Audita's `go test ./scripts -count=1`, -`bash -n scripts/release.sh`, and real `bash scripts/release.sh version` passed; -the wrapper reported `releasekit v0.1.0` and left source module files unchanged. -ReleaseKit's `TestWoodpeckerTagDeliveryTemplate` and -`TestWoodpeckerTagDeliveryUsesTaggedModuleVersion` passed with local Git and -module-proxy fixtures. Both repositories passed their relevant diff checks. - -**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 - -**Completion:** Complete. All ten release-roadmap items map to implemented API, -profile, execution, diagnostics, canonical documentation, and focused behavioral -evidence. The audit confirms default zero-value behavior, independent -module-distribution selections, one coordinated Go suite, source-only -compilation/delivery, and expected-push preflight. Review found no unintended -defaults, restrictions, or stronger guarantees. Audita's migration is recorded -at `17421bc`. - -**Verification:** `go test ./...` and `go run ./internal/apicheck` passed. -Local Markdown destinations and fragments resolved across the documentation; -dependency versions, source revisions, attribution entries, and license texts -were checked. Maintained Woodpecker examples passed their offline fixtures. - -**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. diff --git a/docs/roadmap/model.md b/docs/roadmap/model.md deleted file mode 100644 index 7621c41..0000000 --- a/docs/roadmap/model.md +++ /dev/null @@ -1,149 +0,0 @@ -# Validation API and profile model - -Status: Complete for the agreed v0.2.0 shared validation model. Every selection -and execution path described here is implemented and locally verified; broader -consumer adoption remains in the product roadmap. - -This roadmap describes the shared model that enables the optional validation -capabilities in the [v0.2.0 roadmap](v0.2.0.md). It owns their common API, -configuration, execution, and diagnostic design. The release roadmap owns each -capability's purpose and scope. The [implementation plan](implementation.md) -owns the stages and the agreed API rollout. - -## Rationale and v0.1.0 baseline - -ReleaseKit v0.1.0 exposes `Check` and `Publish` through the root facade. Both -accept `ReleaseRequest` and use shared candidate-validation machinery. Validation -runs the standard offline Go suite, followed by `AdditionalChecks` when supplied. -Selected executable builds follow validation. The CLI maps profile `checks` -commands to the additional-check callback. - -This provides a common procedure and a product-specific extension point. The -request and profile have structured selections for race testing, separate full -vet, package compilation, formatting, Markdown, module distribution, and file -size. Publication also supports an expected push endpoint. - -The model lets consumers declare their choices once while ReleaseKit owns -execution and coordination. This follows [ADR 0002](../adr/0002-routine-releases.md): -shared capabilities should reduce application code and routine developer -decisions. The facade boundaries in [ADR 0001](../adr/0001-public-facade.md) -provide the existing architectural foundation. - -Optional capabilities can serve a small subset of consumers when they remove -application-owned release mechanics and have clear scope, compact configuration, -and proportionate maintenance costs. - -## Target end state - -### One validation specification - -The facade-owned `ValidationSpec` on `ReleaseRequest` has a corresponding -`validation` object in the release profile. Typed Go fields and ordinary JSON -settings express the same supported selections. Related choices, including -base-test and vet settings, are grouped so their relationship is clear. - -The specification includes the agreed capabilities in the -[release roadmap](v0.2.0.md), including optional Markdown boundary enforcement, -independent module-distribution rules, and file-size settings. Its zero value -and an omitted profile object preserve current default validation. Consumers -enable optional checks according to their product needs. - -Go callers and CLI users receive equivalent validation behavior. The CLI owns -profile parsing and presentation; the facade owns the public types and contracts; -internal implementation owns execution. The [implementation plan](implementation.md) -records the selected field names, representations, and completed rollout. - -### Shared coordination - -`Check` and `Publish` pass the same specification through one internal validation -path bound to the captured candidate. ReleaseKit constructs the selected Go -commands, manages its shared environment, determines execution order, and -propagates failures and cancellation. - -Race selection changes the one base suite invocation. Selecting a separate -full-vet pass automatically omits test-time vet. Package-compilation targets -express compatibility checks independently of executable artifact selection. -Consumers obtain this coordination through their declarations. - -Keep the executor straightforward and internal, with ordinary functions for -the selected capabilities. The public model expresses validation choices; -ReleaseKit maintains their execution procedure. Existing candidate rechecks, -offline validation, and source-publication outcomes retain their meaning. - -### Candidate-content inspection - -File-oriented checks share candidate-file enumeration and inspection where -useful. Their scope is the captured candidate, and inspection remains offline -and read-only. Inspect committed candidate contents and define symlink and -submodule handling explicitly in the shared inspection model. Module-distribution -rules inspect the files being released independently of the environment used -to run Go commands. Markdown boundary -validation operates independently of neighboring checkout contents. - -Keep each check's settings together: Markdown validation owns its optional -boundary rule; module-distribution validation owns its independent rule -selections; file-size validation owns its limit and path exclusions. The -[release roadmap](v0.2.0.md) defines the scope and defaults of each capability. - -### Clear responsibility boundaries - -| Concern | Model owner | -| --- | --- | -| Base tests, full vet, and package compilation | Shared validation specification | -| Formatting, Markdown links, module distribution, and file size | Shared validation specification | -| Product-specific assertions and example checks | Existing `AdditionalChecks` callback and profile `checks` | -| Expected authoritative push destination | Publication settings and endpoint handling | -| Executable package, binary name, and artifact targets | Build declaration | -| Hosted destination and credentials | Delivery settings | - -`AdditionalChecks` and profile `checks` remain available for substantive -consumer behavior. Shared capabilities use the validation specification. -Preserve the current behavior of existing declarations as the new options land. - -The expected-endpoint feature remains a publication guard, and `Check` remains -local-only. Selecting package-compilation checks leaves a source-only consumer's -deliverable selection unchanged. Tool installation and dependency preparation -remain separate from offline candidate validation. - -### Consistent diagnostics - -Shared validation failures identify the check and expose useful details to Go -callers. File-oriented checks provide source locations and actionable findings -where applicable, including relevant paths, directives, and measured values. -The CLI presents those details consistently through the ordinary candidate-check -and publication commands. - -Use a small facade-owned error model with stable check identity and support for -underlying error causes and cancellation. Preserve `errors.Is` and `errors.As` -behavior across internal conversions and facade wrapping. Exact error types -and diagnostic fields are proposed in the [implementation plan](implementation.md). - -Validation failures and publication outcomes have distinct meanings. Existing -publication states continue to describe whether publication was attempted, -confirmed, conflicted, or remains uncertain. The model preserves the existing -failure-stopping behavior of the candidate workflow. - -## Implementation - -The [implementation plan](implementation.md) records the completed rollout and -verification. The facade and CLI profile expose equivalent selections for the -single test suite, separate full vet, package compilation, formatting, Markdown, -module distribution, file size, and the expected publication endpoint. Shared -execution, ordering, diagnostics, cancellation, and failure stopping are -implemented by the owners described above. The maintained Woodpecker template -and Audita's local wrapper use the module-selected ReleaseKit version; see the -[v0.2.0 roadmap](v0.2.0.md) and [delivery guide](../consumers/delivery.md). - -## Adoption evidence - -Self-contained integration fixtures evaluate all three known consumer shapes: -Audita's default validation and executable builds; ConfigKit's selected test, -vet, and library compilation checks; and PromptKit's shared validation plus -substantive example assertions. Audita's module-selected CI migration is -committed at `17421bc`; the other consumer migrations remain separate adoption -work. - -The model gives each adopting consumer a small declaration and the same routine -release operation. Shared execution and diagnostics cover the agreed v0.2.0 -capabilities while product-specific work remains in the existing extension -point. diff --git a/docs/roadmap/releasekit.md b/docs/roadmap/releasekit.md index a6517f9..3fa2daf 100644 --- a/docs/roadmap/releasekit.md +++ b/docs/roadmap/releasekit.md @@ -1,210 +1,43 @@ -# ReleaseKit: shared release process +# ReleaseKit adoption and deployment roadmap -Status: The v0.2.0 implementation, policy adoption, and architecture -remediation are complete. Audita's module-selected local and CI integration is -committed at `17421bc`; broader consumer adoption and live deployment remain. +Status: Pending consumer adoption and live deployment. The v0.2.0 implementation +and its remediation are complete. -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 initial foundation, policy adoption, and remediation plans are preserved -in Git history; the current v0.2.0 completion evidence is in the -[implementation plan](implementation.md). +The [v0.2.0 release note](../releases/v0.2.0.md) summarizes the implemented +capabilities. The [internal inventory](../internal/overview.md) records their +owners and local verification. Completed plans and review findings remain in +Git history. The [architecture policy](../policy/architecture.md) and accepted +ADRs own the selected architectural constraints. -## Opportunity +## Remaining work -All six repositories follow the same base release policy. Their release scripts -repeat stable-version parsing, candidate and release-note checks, local and -remote tag checks, validation of one captured commit, explicit Git publication, -and recovery guidance for uncertain pushes. They differ in publication approach, -tag type, validation commands, and artifact delivery. The mechanics of embedding -a release version and cross-building an application are further candidates for -standardization. +- Choose the broader consumer integration test plan and migration sequence for + PromptKit, ConfigKit, Notarius, Narratio, and Scriptorium. Evaluate API clarity, + product-specific checks, and the infrastructure removed from each repository. +- Adopt the common publication, validation, runtime-version, build, and delivery + conventions where they apply. Keep product identity, compatibility decisions, + and substantive application checks with each consumer. +- Provision delivery credentials and activate ReleaseKit and consumer Woodpecker + workflows as part of deployment. The maintained consumer template selects + tooling from the released application's module configuration. +- Verify live Gitea delivery and Woodpecker execution. Current verification uses + local Git and HTTP fixtures; live deployment remains unverified. +- Measure realized reductions in consumer release infrastructure after migration. + Audita's module-selected local and CI integration is committed at `17421bc`. -If the projects deliberately standardize publication approach and tag type, -ReleaseKit can own most of the repeated release-process code. The current six -repositories contain 942 lines of release shell scripts and 742 lines of -dedicated release tests, or 1,684 lines total. A directional estimate is that -roughly 1,000–1,250 lines could leave those repositories: about 450–500 lines -of publication scripts, 150–250 lines of checks and builders, and 400–500 lines -of repeated publication tests. ReleaseKit would gain its own implementation and -tests, so this is a reduction in local code, not a net line-count saving. +## Proposals and deferred work -## Selected publication standard - -1. Prepare and commit a version-matched note at `docs/releases/.md`. -2. Publish the candidate commit to authoritative `main` before invoking the - release command. -3. Run one command that checks the candidate and unused stable version, runs - that repository's offline candidate validation once, and rechecks mutable - state. -4. Create an annotated tag at the validated commit with a message derived from - the checked-in note. Push only that exact tag object to the authoritative - endpoint. A successful tag push completes the source release. -5. Treat hosted release pages and binary assets as asynchronous delivery with - their own status. Do not poll CI or require artifact availability to declare - the source release complete. - -This would replace Audita's atomic branch-and-tag push, ConfigKit's and -Notarius's branch push during the release command, and Audita's, Notarius's, -and Narratio's lightweight tags. Those changes require updates to each -repository's adopted release policy and procedure; they are not merely code -cleanup. - -## Architecture - -[ADR 0001](../adr/0001-public-facade.md) owns the accepted facade decision. -The [architecture policy](../policy/architecture.md) owns the adopted -responsibility and dependency rules, including the runtime version boundary. -The root `releasekit` package provides the public facade for candidate -validation, source publication, selected-target builds, and tagged-source -delivery. The Gitea page and asset-delivery client is integrated through that -facade and the CLI. The separate public `buildinfo` package provides lightweight -runtime version access. - -Each facade owns its public named types and documented contracts. Public -operations, inputs, outcomes, errors, and callbacks express deliberately -selected consumer needs. Handles retain private implementation state; explicit -forwarding and conversions connect the public contracts to internal -representations. - -Git operations, Go toolchain execution, Gitea integration, and orchestration -bookkeeping belong under Go's `internal/` boundary. Dependency direction runs -from the facades into internal implementation, with internal collaborators using -contracts defined inside that boundary. Implementation packages can evolve -while the supported public contracts retain their compatibility obligations. - -The `buildinfo` facade keeps runtime version access lightweight. Applications -read their embedded version through its supported accessor. ReleaseKit's builder -and runtime implementation own the linker symbol and injection mechanism -together. - -The `buildinfo` facade follows three constraints: - -- Its public API exposes only runtime information justified by consumer needs. -- Its implementation uses the standard library and a small internal dependency - graph independent of release orchestration. -- Dependency checks protect that boundary, and build-and-run integration tests - verify that the builder injects the selected version and the public accessor - reports it correctly. - -The release executable calls the orchestration facade and handles command -parsing, output, and exit codes. Library errors and outcomes report meaningful -publication state, including partial progress and uncertainty. Go declarations -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 protect facade ownership. -External-package behavioral tests protect error identity, value ownership, -callback lifetime, and observable outcomes across forwarding and conversions. - -## Shared tool boundary - -Provide a versioned ReleaseKit executable backed by a Go library. Existing -shell entry points can become short invocations of that executable. A library -alone would still require a caller in every shell-driven repository. - -ReleaseKit should own: - -- stable-version parsing and committed-note identity checks; -- authoritative Git endpoint resolution, candidate capture, clean `main` and - remote-branch agreement checks, and unused local/remote tag checks; -- one validation invocation bound to the captured candidate, followed by cheap - rechecks before publication; -- annotated-tag creation and verification, explicit tag-object push, and one - bounded authoritative-ref check after a failed or ambiguous push; -- a standard version accessor in the public `buildinfo` facade, backed by - release-build injection of the selected tag; -- a cross-build API that accepts the application's main package and selected - targets, initially Linux amd64, Linux arm64, and macOS arm64 (Go's - `darwin/arm64`), including an empty set for source-only projects; -- consistent release build flags and asset naming, plus a host-runnable build - that checks the executable's reported version; and -- Git publication tests using temporary local remotes, including remote - advancement, rejected pushes, lost acknowledgments, and unavailable remotes. - -Each repository should retain its product name, compatibility decisions, -candidate-specific checks, main package, selected build targets, delivery -declaration, and a small test of its ReleaseKit wiring. For example, PromptKit -exercises its consumer examples. Applications would adapt their existing -version output to use the `buildinfo` accessor; one agreed version command -or flag would let ReleaseKit smoke-test a host-runnable build the same way. -Cross-built binaries would use the same injection mechanism, but compilation -alone would not establish that they run correctly on another platform. -ReleaseKit should run the selected checks and builds without silently adding -binary gates to source-only projects. - -The build API should own the mechanics rather than require each application to -provide a custom linker symbol or shell loop. The initial target list reflects -the current projects, not a permanent limit on future platforms. It should -support both candidate cross-build checks and artifact builds from the tagged -source, using the same version and target selection. - -## Woodpecker and Gitea delivery - -A common tag-triggered Woodpecker workflow can run ReleaseKit against the -tagged source. Repository-local YAML should declare the pinned tool image and -credentials; each repository's ReleaseKit configuration should declare its -delivery destination and any binary main package and target set. ReleaseKit can -own version injection, cross-builds, checksum generation, and delivery. All -projects should receive hosted Gitea -release pages. Source-only repositories declare zero binary assets and deliver -the committed release note without a binary build or checksum manifest. - -The shared delivery command should create or find the release for the tag, -use the checked-in note, and add declared binary assets and their checksum -manifest where applicable. A retry should inspect existing assets, verify -matching content, add only missing items, and stop on a conflict. -An existing checksum manifest must remain consistent with any later addition. -The release and its attachments are separate remote operations, so partial -delivery must be expected and reported clearly. - -Audita, Narratio, and Scriptorium currently use the Woodpecker release plugin -with `file-exists: skip` and `overwrite: false`. Those settings avoid deliberate -replacement by filename, but they do not prove that a rebuilt file has the -same bytes as a previously published file. Content comparison would be a -reason to implement a shared Gitea delivery client rather than rely solely on -the plugin's skip behavior. - -Hosted pages are selected for source-only projects, including PromptKit, -ConfigKit, Notarius, and ReleaseKit. Adoption adds a page deliverable and delivery -credentials to their procedures while preserving successful tag publication as -source completion. The initial implementation should support both page-only and -binary delivery through the same facade and command. - -## Failure states - -ReleaseKit should report source publication and artifact delivery separately: - -| Event | Result | -| --- | --- | -| Candidate validation or a pre-push guard fails | No release was published; correct and validate the candidate again. | -| Tag push reports success | Source release is complete; delivery may still be pending. | -| Tag push fails or its acknowledgment is lost | Query the authoritative ref once. Confirm success only if the exact intended tag object is present on the intended commit; otherwise report failed or unknown status and retain the local tag. | -| Woodpecker or Gitea delivery fails after tag publication | Keep the source release successful. Retry missing delivery from the immutable tag after checking existing content. | -| Published source or content needs correction | Publish a new version; never replace content under the published version. | - -## Consumer adoption target - -All six projects should use the same selected publication, runtime version, -build, and delivery conventions where those responsibilities apply. Repository -entry points should contain only tool invocation and product-specific settings -or checks. Shared mechanics and their repeated tests belong in ReleaseKit. - -Application runtime code should obtain version information through `buildinfo`. -Source-only libraries need no runtime import or automatic binary deliverable. -Projects declaring binaries should use the common target selection and version -injection; hosted delivery should use content-aware retries for both page-only -and binary releases. -Existing published tags, notes, pages, and assets retain their historical contents. - -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. +- Optional recognizable-credential checks remain an unevaluated suggestion from + PromptKit's feature request. Evaluate their detection scope, synthetic-fixture + handling, false-positive costs, and maintenance benefit before selecting shared + support. The proposal establishes no mandatory credential gate. +- ReleaseKit executable binary distribution remains deferred until deliverables + are deliberately selected. Selecting binaries would require delivery + declarations, target checks, automation responsibilities, and corresponding + release policy and procedure updates. +- Evaluate a maintained ReleaseKit CI image or specialized validation/build + settings when a demonstrated consumer need justifies their maintenance cost + under [ADR 0002](../adr/0002-routine-releases.md). ## Representative migration review @@ -226,40 +59,3 @@ The self-contained ReleaseKit fixtures exercise a meaningful source-only compatibility check through local Git publication, and a `buildinfo` binary consumer with selected targets through local HTTP delivery. These are separate publication and delivery operations. - -## Remaining work - -- Use the [v0.1.0 baseline](../releases/v0.1.0.md) for initial consumer - integration under the [maintainer procedure](../release.md). Consumers that - adopt the maintained tag workflow select ReleaseKit through the tagged - source's `go.mod` rather than a separate workflow version value. -- Choose the broader consumer integration test plan and migration sequence. - Evaluate API clarity, product-specific checks, and the infrastructure removed - from each consuming repository. -- Provision delivery credentials and activate consumer Woodpecker workflows - as part of deployment. The tagged consumer's module configuration selects - the ReleaseKit version used by the maintained workflow. -- Verify live Gitea delivery and Woodpecker execution. Existing verification uses - local Git and HTTP fixtures; no live deployment has been verified. -- Keep ReleaseKit executable binary distribution deferred until deliverables - are deliberately selected. Selecting binaries would require delivery - declarations, target checks, automation responsibilities, and corresponding - release policy and procedure updates. -- Evaluate a maintained ReleaseKit CI image or specialized validation/build - settings when a demonstrated consumer need justifies their maintenance cost - under [ADR 0002](../adr/0002-routine-releases.md). - -## Reviewed implementations - -- [PromptKit release script](../../../promptkit/scripts/release.sh), - [checker](../../../promptkit/scripts/release-check.sh) -- [ConfigKit release script](../../../ConfigKit/scripts/release.sh), - [checker](../../../ConfigKit/scripts/release-check.sh) -- [Audita release script](../../../audita/scripts/release.sh), - [Woodpecker job](../../../audita/.woodpecker/release.yml) -- [Notarius release script](../../../notarius/scripts/release.sh), - [checker](../../../notarius/scripts/check-release-source.sh) -- [Narratio release script](../../../narratio/scripts/release.sh), - [Woodpecker job](../../../narratio/.woodpecker/release.yml) -- [Scriptorium release script](../../../scriptorium/scripts/release.sh), - [Woodpecker job](../../../scriptorium/.woodpecker/release.yml) diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md deleted file mode 100644 index 34b959c..0000000 --- a/docs/roadmap/remediation.md +++ /dev/null @@ -1,430 +0,0 @@ -# ReleaseKit implementation remediation - -Status: All nine findings addressed. - -The v0.2.0 review covers committed state `edd670e` and the implementation -commits after `89981ab`, against the [implementation plan](implementation.md), -[feature roadmap](v0.2.0.md), [model roadmap](model.md), accepted ADRs, and -applicable repository policies. Both ReleaseKit and Audita had clean worktrees -when inspected. The review changed only this document; the resolutions below -record subsequent remediation. - -## Foundation review history - -Reviewed committed implementation `f53354b`, covering the eight foundation -commits after `0c7129a`, against the [implementation plan](implementation.md), -[model roadmap](model.md), accepted ADRs, and applicable repository policies. -The worktree was clean when review began. This document records required fixes; -production code was unchanged during the review. - -## Foundation architecture assessment - -The root orchestration facade and independent `buildinfo` runtime facade retain -their intended dependency direction. Both candidate operations share request -conversion and `internal/candidate.Validate`. Candidate capture, product -callbacks, builds, and rechecks retain their owners; `internal/validation` owns -the default Go suite, structured failures, and committed-tree inspection. -Publication retains endpoint guards, tag operations, and recovery. The CLI -shares profile conversion and owns output and exit classification. - -The public error types belong to the root facade, and conversion preserves the -underlying error chain. Candidate inventory reads committed entries and blobs, -with separate handling for symlinks and gitlinks. Its default validation path -does not load that inventory. - -The absent `ValidationSpec`, request/profile selections, optional checkers, CI -tooling changes, and expected-endpoint option are intentionally deferred under -the agreed incremental rollout. Their absence is consistent with foundation -scope. The defects below affect the implemented foundation, including helpers -that subsequent checkers will use. - -## 1. P2: Expanding symlink cycles do not terminate or honor cancellation - -**Resolution:** Addressed. The resolver tracks active symlink expansions, -releases them before traversing the remaining destination, and checks context -cancellation during traversal. Regression coverage includes direct and mutual -expanding cycles, finite repeated links, and cancellation. -`go test ./internal/validation` passed. - -**Owner:** [candidate destination resolver](../../internal/validation/tree.go), -`CandidateTree.ResolveDestination`, especially the restart loop and cycle key. - -The cycle key combines the symlink path with the unresolved suffix. For a -committed symlink `loop -> loop/child`, resolving `loop` visits suffixes of -increasing length. The key never repeats. Cached link reads do not consult the -context, and the resolver loop has no cancellation check. Resolution can keep -consuming CPU and memory after cancellation. - -**Evidence:** A temporary overlay test using committed-entry metadata and -cached symlink text confirmed that the operation neither returned a cycle -classification nor stopped within 150 ms, despite a 20 ms context deadline. -Existing tests cover a two-link cycle whose suffix stays constant. - -**Required remediation:** Detect recursive symlink expansion using the active -expansion chain and honor context cancellation during traversal. Preserve -legitimate finite paths that encounter a symlink again after an earlier -expansion has completed. Keep cycle detection separate from any arbitrary -hop/path-length limit; such a limit was not requested. - -**Verification:** Add focused cases for direct and mutual expanding cycles, -finite repeated symlink traversal, and cancellation. Keep the fixture local -and bounded even when testing the broken behavior. - -## 2. P2: Path cleanup changes symlink traversal and checkout classification - -**Resolution:** Addressed. Destination components and symlink targets are -traversed in order, with parent traversal applied to resolved directories. -Missing entries and regular-file traversal remain observable. Regression tests -cover both destination and symlink-target parent components and confirm that -neighboring files do not change classification. -`go test ./internal/validation` passed. - -**Owner:** [candidate destination resolver](../../internal/validation/tree.go), -initial destination construction and construction after symlink expansion. - -`path.Join`/`path.Clean` eliminate `..` components before intervening symlinks -are resolved. This changes the destination rather than resolving it. It can -also discard a symlink that crosses the checkout boundary. - -**Evidence:** With `docs/link -> ../nested/inner`, resolving -`docs/link/../file.md` returns `docs/file.md` instead of `nested/file.md`. -With `link -> ../neighbor`, `link/../README.md` is incorrectly classified as -the captured root's `README.md`, hiding its outside-checkout destination. -Both failures were reproduced with overlay tests. PromptKit's starting -convention resolves paths before checking their relation to the checkout. - -**Required remediation:** Walk path components and symlink expansions in order. -Apply parent traversal to the resolved directory, retaining missing-file and -non-directory observations where traversal encounters them. Derive checkout -classification from that traversal, using candidate entries throughout. - -**Verification:** Cover `..` following internal and external symlinks and -following missing or regular-file components. Assert resolved identities and -boundary classifications independently of neighboring filesystem contents. - -## 3. P2: Committed-file inspection can fetch from a promisor remote - -**Resolution:** Addressed. Candidate tree, size, and blob reads share a local -Git command helper that disables lazy fetching and transport access per child -process. Missing blobs report local unavailability, and Git process causes -remain wrapped. Partial-clone tests cover missing blobs and missing trees, -instrument transport attempts, and verify the object database stays unchanged. -`go test ./internal/git ./internal/validation` passed. - -**Owner:** [Git source readers](../../internal/git/source.go), `ReadTree`, -`populateBlobSizes`, and `ReadBlob`. - -The new readers invoke ordinary Git object-reading commands without suppressing -automatic fetching of missing promisor objects. Inspecting a filtered checkout -can therefore initiate remote access during the promised offline operation. -Successful fetching can also populate the checkout's object database. - -**Evidence:** A local `--filter=blob:none --no-checkout` clone contained commit -and tree objects but no blobs. Its promisor URL was replaced with a synthetic -SSH destination, and a local SSH stub recorded attempts and exited. Calling -`ReadCandidateTree` invoked that stub through `cat-file --batch-check` and -returned a promisor-fetch error. No external host was contacted. Ordinary -fully populated repository tests do not exercise this behavior. - -**Required remediation:** Make these candidate object reads explicitly local -and suppress lazy fetching using a mechanism supported by the applicable Git -version. Report unavailable local objects with preserved causes. Keep source -preparation and network-capable publication/delivery operations in their -existing separate boundaries; a global ban on partial clones is unnecessary. - -**Verification:** Inspect a local filtered-clone fixture with unavailable blobs -and an instrumented remote transport. Assert that metadata/content requests -fail locally when necessary and never invoke that transport. Retain successful -reads from fully populated candidates. - -## 4. P2: Public and CLI error presentation loses diagnostic information - -**Resolution:** Addressed. Public errors use the internal diagnostic formatter -with explicit conversions, including findings, targets, directives, -measurements, and causes. Matching converted diagnostics reuse their contextual -cause's rendering once. The CLI preserves outer wrappers, and callback errors -retain their public identity. Regression tests cover both candidate operations -and caller-created errors with and without causes. -`go test . ./cmd/releasekit ./internal/validation ./internal/apicheck` and -`go run ./internal/apicheck` passed. - -**Owners:** [public diagnostics](../../validation_error.go), -`ValidationError.Error` and its formatter; [CLI presentation](../../cmd/releasekit/main.go), -`candidateFailureText`; [internal formatting](../../internal/validation/diagnostic.go). - -Two branches lose information: - -- A caller-created `ValidationError` with a cause returns only `Cause.Error()`. - Its check, findings, and measurement disappear from the textual diagnostic. - Converted built-in failures happen to work because their retained internal - cause already formats those details. -- The CLI extracts an inner `ValidationError` with `errors.As` and formats that - inner value. For a callback-supplied public error, this drops the candidate - wrapper added by `candidate.Validate`. - -The public and internal formatters also duplicate the finding/measurement -formatting procedure, making it easier for their behavior to diverge. - -**Evidence:** A public error with check `go-format`, a `main.go:3` finding, and -cause `inspection failed` renders only `inspection failed`. A candidate-wrapped -callback diagnostic loses its captured-commit context through -`candidateFailureText`. Both failures were reproduced with temporary overlay -tests. Existing tests exercise only converted Go-suite failures. - -**Required remediation:** Share diagnostic formatting behind the facade with -explicit conversions. Preserve the full contextual chain when presenting an -error and include caller-supplied structured detail alongside its cause. -Ensure converted built-in failures render once. Retain `errors.Is`/`errors.As` -and existing exit/publication classifications. - -**Verification:** Cover public errors with and without causes, callback errors -with candidate context, and converted built-in failures. Assert useful fields, -cause identity, context, and absence of duplicate diagnostics without fixing -complete message wording as a contract. - -## 5. P2: Absolute paths inside the checkout are classified as outside - -**Resolution:** Addressed. Absolute destinations and symlink targets within the -captured repository directory map to candidate paths before component -traversal. Absolute paths with similar external prefixes remain outside. -Regression tests also retain symlink-before-parent semantics and demonstrate -that removed committed files resolve while live-only files remain missing. -`go test ./internal/validation` passed. - -**Owner:** [candidate destination resolver](../../internal/validation/tree.go), -the absolute-destination and absolute-symlink branches. - -Both branches classify every path beginning with `/` as outside the checkout. -This substitutes path syntax for the requested checkout boundary. An absolute -path naming a file inside the captured repository is also labeled outside by this -classification. A later boundary-enforcing checker would consequently apply -an additional restriction that the user did not select. - -**Evidence:** For repository directory `/checkout/project` with captured -`README.md`, the resolver classifies `/checkout/project/README.md` as -outside-checkout. An overlay test confirmed this. PromptKit's starting checker -uses resolved containment and accepts an existing absolute destination within -its checkout; the user selected that convention as the starting specification. -The implementation plan calls for checkout-boundary classification and -committed-file access, without establishing an absolute-path prohibition. - -**Required remediation:** Map absolute destinations and symlink targets that -name paths within the captured repository directory back to candidate-relative -paths, then resolve against committed entries. Classify actual external paths -as outside without reading them. A different absolute-path policy requires an -explicit scope decision. - -**Verification:** Cover absolute direct destinations and absolute symlinks -inside and outside the captured root, including similar root prefixes. Use -committed entries for existence; neighboring files remain irrelevant. - -## 6. P3: Future Go command behavior appears in implemented internal documentation - -**Resolution:** Addressed. The internal guide describes current environment -reuse and links to the roadmap for proposed command coordination and Markdown -behavior. Its implemented executor, candidate-file mechanics, and checker -integration guidance remain in place. Local links and fragments were checked. - -**Owner:** [shared validation guide](../internal/validation.md), -`Prospective Go command recipe`. - -The section describes race, separate vet, and package-compilation behavior that -has not been implemented. Although it is labeled prospective, the -[documentation policy](../policy/documentation.md) assigns future behavior to -`docs/roadmap/` and limits other documents to their implemented boundary. - -**Required remediation:** Replace the future command recipe with a link to the -roadmap's coordination design. Keep the internal guide's implemented executor, -environment reuse, candidate-file mechanics, and checker integration procedure. -Document exact command behavior in its canonical owners when the capabilities -land. - -**Verification:** Review the guide against the current executor and check its -links. Preserve the distinction between foundation completion and completed -optional features. - -## Foundation review evidence and limits - -- `go test ./...` passed; unchanged packages used cached results. -- `go run ./internal/apicheck` passed. -- Recent production-code, test, and documentation diffs were inspected. The - existing tests protect default execution, callback failure handling, facade - error identity, publication state, and representative committed-tree cases. -- Temporary Go overlays outside the worktree reproduced the additional cases - above against current code. Their expected failures are review evidence, - not changes to the committed test suite. -- No new universal release gate, public validator-registration framework, - consumer-check requirement, or change to publication completion was found. - Finding 5 identifies an additional boundary restriction; findings 1–4 - identify failures to satisfy the intended behavior. Finding 6 concerns - documentation ownership. - -This review evaluates the completed foundation. It does not establish that the -remaining v0.2.0 features have been implemented or that their eventual checker -semantics are verified. - -## v0.2.0 architecture assessment - -The intended package and ownership boundaries are implemented. The root -`releasekit` facade owns requests, validation selections, diagnostics, and -publication/delivery outcomes. The separate `buildinfo` facade depends on the -standard library and `internal/runtimeinfo`; its graph remains independent of -orchestration and the new parsing dependencies. - -`Check` and `Publish` use the same request conversion and -`internal/candidate.Validate`. `internal/validation` coordinates one native -test suite, selected full vet and static package compilation, and selected -committed-file checks. Formatting, distribution, file-size, and Markdown checks -share candidate inventory and lazy blob access. Goldmark and `x/mod/modfile` -remain internal dependencies. Product callbacks, artifact building and version -injection, publication guards/recovery, and hosted delivery retain their owners. -The expected push URL is compared exactly in publication preflight; local -checking ignores it. The CLI owns profile conversion, presentation, and exits. - -The consumer Woodpecker template verifies tagged source before selecting the -tool through temporary module metadata. Audita's local wrapper and workflow -adopt that approach in commit `17421bc`; the inspected declarations preserve -its existing dependency version, image, secret name, and release profile. - -All ten feature areas are present. The review identified three behavior gaps -within Markdown validation and self-bootstrap. Finding 8 imposed unrequested -existence/boundary checks on image alternative text. Finding 9 effectively -required a prepopulated tool module cache. The review found no -additional public package, validator-registration framework, universal optional -check, arbitrary inspection limit, or change to source-publication completion. - -## 7. P2: Heading anchors omit autolink display text - -**Resolution:** Addressed. Heading extraction includes autolink display labels. -Parser coverage includes URL/email headings and surrounding text; committed -fragment checks cover both forms. The new cases failed before the fix, and -`go test ./internal/validation` passed afterward. - -**Owner:** [Markdown heading extraction](../../internal/validation/markdown.go), -`markdownHeadingText`, lines 115–139. - -The agreed convention derives anchors from visible heading text. The extractor -handles text and code spans and recurses through formatting nodes, but Goldmark's -`ast.AutoLink` stores its visible text in `Label` and has no text children. -URL and email autolinks therefore disappear from the heading before slugging. - -**Evidence:** A temporary overlay probe against the current checker used: - -```markdown -# -[section](#httpsexampleinvalid) -``` - -The computed anchor was the empty string, and the section link failed with -`heading anchor does not exist`. The same failure occurred for a heading -`# ` and fragment `#maintainerexampleinvalid`. -Existing anchor tests cover text, code, formatting, entities, Unicode, and -duplicates, while existing autolink coverage only checks URL extraction. - -**Required remediation:** Include an autolink's display label in heading text -before applying the existing normalization and duplicate-anchor algorithm. -Preserve the current HTML, code-span, and ordinary link-label handling. - -**Verification:** Add parser coverage for URL and email autolinks inside headings, -including surrounding text, and a representative committed-fragment check. -Keep external destination availability outside this offline capability. - -## 8. P2: Image alternative text creates additional release requirements - -**Resolution:** Addressed. Destination extraction records an image source and -skips its alternative-text children. Regression coverage exercises nested -images/links, missing anchors, and outside-checkout label syntax under both -boundary settings. Real linked images still report missing sources and link -targets. The regression failed before the fix, and -`go test ./internal/validation` passed afterward. - -**Owner:** [Markdown link extraction](../../internal/validation/markdown.go), -`parseMarkdown`, especially the image branch and AST traversal at lines 65–110. - -After recording an image destination, the walker continues through the image's -label children and records nested link/image syntax as independent destinations. -Those children contribute plain alternative text to the rendered image. The -checker consequently requires files and anchors that the document does not -navigate to or load, and boundary enforcement can also reject those labels. - -**Evidence:** With only `image.png` committed, this valid Markdown is rejected -for missing `missing.png`: - -```markdown -![![inner](missing.png)](image.png) -``` - -Goldmark's own renderer produces `inner`. -Similarly, `![[label](missing.md)](image.png)` renders an image with alternative -text `label`, while ReleaseKit records and validates `missing.md` as a link. -Temporary overlay probes confirmed both extraction and rendering; the first -case also reproduced the checker failure against committed Git contents. - -**Required remediation:** Record the outer image destination and treat its label -as alternative text during destination extraction. Preserve real linked images: -`[![logo](badge.png)](guide.md)` has an image source and an enclosing link target -that both require validation. This change removes the unintended requirement -without narrowing supported Markdown syntax. - -**Verification:** Cover nested image/link syntax in alternative text, including -an outside-checkout label destination under boundary enforcement. Verify that -real linked images still report missing image sources and missing link targets. - -## 9. P1: ReleaseKit's source-delivery bootstrap fails with an empty module cache - -**Resolution:** Addressed. Self-bootstrap uses normal Go dependency access for -its readonly tool build after tag verification. The maintained workflow test -starts with an empty module cache and a local HTTP module proxy, builds a tool -with an external dependency, and verifies execution, clean tagged source, and -temporary-output cleanup. A wrong commit stops before Go or proxy access. The -regression failed before the fix and passed afterward. The delivery guide now -describes tool dependency access and its separation from offline validation. -The uncached offline suite, `go run ./internal/apicheck`, and local documentation -link/fragment checks passed after all three fixes. - -**Owners:** [source-delivery workflow](../../examples/woodpecker/releasekit-source-delivery.yml), -lines 27–31; [workflow verification](../../cmd/releasekit/woodpecker_test.go), -`TestWoodpeckerSourceDeliveryTemplateSelfBootstraps`; and the -[delivery guide](../consumers/delivery.md#woodpecker-tag-workflows). - -The source template sets `GOPROXY=off` and `GOSUMDB=off` before building the tool -and provides no tool dependency preparation. ReleaseKit now imports Goldmark and -`x/mod` through validation, so the standard Go image needs those modules to build -`./cmd/releasekit`. On a fresh runner the workflow stops before `ci-deliver` and -the hosted note page is never delivered. The previous dependency-free tool did -not expose this problem. The guide describes cache mounts as optional, while -the current implementation effectively requires a prepopulated module cache. - -**Evidence:** Running the template's build command against `edd670e`, with a -temporary empty `GOMODCACHE` and its workspace/toolchain/proxy settings, returned -exit 1. Both dependencies reported `module lookup disabled by GOPROXY=off`. -The existing self-bootstrap test builds a synthetic command that imports only -`fmt` and `os`, so it cannot detect missing tool dependencies. - -**Required remediation:** Allow ordinary tool dependency preparation after tag -verification. A network-capable readonly tool build or an explicit preparation -step can populate the module cache while preserving tagged source. Honor normal -Go proxy/private-module/cache settings. Keep offline candidate validation and -application artifact compilation in their existing owners. Update the template -and guidance together; a prewarmed cache remains an optional deployment choice. - -**Verification:** Exercise the maintained self-bootstrap commands with an empty -module cache and a local module proxy serving a real external tool dependency. -Verify preparation follows tag/commit verification, the executable runs, tagged -module files remain unchanged, and temporary output is cleaned up. Existing -delivery tests retain ownership of hosted page behavior. - -## v0.2.0 review evidence and limits - -- Reviewed recent production, test, template, and documentation changes and - their shared request, execution, and dependency boundaries. -- `GOPROXY=off GOSUMDB=off GOTOOLCHAIN=local go test -count=1 ./...` passed. -- `go run ./internal/apicheck` passed. Direct dependency inspection of - `buildinfo` confirmed its standard-library/runtime-only graph. -- Inspected Audita commit `17421bc` and its actual local and CI bootstrap files. -- Temporary overlay tests outside the worktree reproduced findings 7 and 8. - Goldmark's renderer confirmed the alternative-text semantics. A separate - temporary empty module cache reproduced finding 9. These probes are review - evidence; production code and the committed test suite remain unchanged. -- Existing tests passed but omitted these cases at review time. The resolutions - above record completed fixes and regression coverage. diff --git a/docs/roadmap/v0.2.0.md b/docs/roadmap/v0.2.0.md deleted file mode 100644 index 953b726..0000000 --- a/docs/roadmap/v0.2.0.md +++ /dev/null @@ -1,299 +0,0 @@ -# ReleaseKit v0.2.0 roadmap - -Status: Implemented and locally verified. Stages 1–15 are complete; see the -[implementation plan](implementation.md) for the completion record. Audita's -module-selected local and CI integration is committed at `17421bc`. Broader -consumer adoption, architecture review, hosted deployment, and release tagging -remain separate work. - -This roadmap catalogs improvements to ReleaseKit v0.1.0. Each item records its -rationale, target state, and relevant scope decisions. The -[implementation plan](implementation.md) owns the staged work and verification -evidence. - -The priorities in [ADR 0002](../adr/0002-routine-releases.md) guide this work: -minimize application-owned release code, duplicated mechanics, and routine -developer decisions through a standard, minimal API. - -## 1. Establish the shared validation API and profile model - -### Rationale and baseline at plan start - -The shared validation foundation and its remediation are complete. ReleaseKit -has common candidate execution, facade-owned diagnostics, committed-file -inspection, and a product-specific additional-check extension point. The -optional v0.2.0 capabilities now have functioning API/profile selections and -checker implementations. - -The [validation-model roadmap](model.md) records this enabling work and its -rationale. A common model lets consumers declare choices once and receive -ReleaseKit's shared execution and coordination. - -### Target end state - -A facade-owned validation specification and corresponding profile object -express the agreed optional checks with consistent defaults and behavior. -ReleaseKit owns coordination and diagnostics through the existing `Check` and -`Publish` operations. Product-specific checks, publication expectations, -artifact builds, and delivery retain their distinct responsibilities. - -The implemented API and profile provide equivalent declarations for the -validation capabilities below through the existing shared foundation. - -## 2. Use the application's module-selected ReleaseKit version in CI - -### Rationale and baseline at plan start - -At the v0.1.0 planning baseline, the maintained CI template selected ReleaseKit -through a separate `RELEASEKIT_VERSION` value and invoked its command with an -explicit `@version`. - -Audita demonstrates the resulting duplication: its local release wrapper builds -ReleaseKit using the application's module dependencies, while CI independently -selects ReleaseKit v0.1.0. A dependency upgrade can leave CI using an older tool. -Maintainers must remember to coordinate both declarations. - -Using the application's module-selected version for both paths gives upgrades -one dependency declaration and keeps local publication and CI delivery aligned. -Stages 12–14 changed the maintained template and Audita's workflow to this -approach; the current [adoption guidance](../consumers/delivery.md#woodpecker-tag-workflows) -describes it. - -### Target end state - -For applications that declare ReleaseKit as a module dependency, the standard -CI integration uses the ReleaseKit version selected by the released source's -module configuration. The workflow verifies the triggering tag and commit and -checks out that source before resolving and building the release tool. - -Local publication and CI delivery use the same module-based selection approach. -Updating the application's ReleaseKit dependency updates both paths. The -consumer workflow supplies the CI event, environment, and credentials; the -application profile continues to supply product and delivery settings. - -Tool bootstrap and dependency preparation remain distinct from offline -validation and builds. Source publication and hosted delivery retain separate -outcomes. ReleaseKit's own source bootstrap and consumers using a separately -installed tool remain supported use cases. - -Audita adopted the module-based integration as the first consumer migration in -commit `17421bc`. - -The maintained template and Audita's first migration now use one ReleaseKit -module declaration for local and hosted integration. - -## 3. Select one base test invocation, including race testing - -### Rationale and baseline at plan start - -ReleaseKit always runs its standard offline Go suite before additional product -checks. ConfigKit selects race-enabled testing for its release validation. -PromptKit requests the same capability for its concurrent execution and -backend-capacity management. -Expressing that selection as an additional check would execute the suite twice -and leave the application coordinating shared validation mechanics. - -A small declarative selection lets consumers retain their chosen validation -while ReleaseKit owns the procedure and runs the suite once. - -### Target end state - -The public Go API and profile support selecting race testing for the single -base Go test invocation. With no selection, the current default applies. -`Check` and `Publish`, including their CLI forms, use the same selection. - -ReleaseKit constructs the invocation and owns candidate capture, full-suite -scope, offline execution, ordering, and failure reporting. Additional product -checks remain available after shared validation. Selecting race testing reports -unavailable prerequisites clearly and preserves the selected validation. - -The API and profile now let ConfigKit and PromptKit select a race-enabled suite -once and remove the corresponding consumer-owned test invocation when they -adopt the selection. - -## 4. Offer a separate full vet pass - -### Rationale and baseline at plan start - -ConfigKit and PromptKit currently run a full `go vet` pass in addition to their -test suites. ReleaseKit relies on test-time vet unless a consumer supplies an -additional command. That leaves consumers coordinating vet coverage and -repeated work. - -### Target end state - -A public API and profile option selects a separate full vet pass within shared -candidate validation. ReleaseKit automatically omits test-time vet when that -pass is selected. The base suite runs once, followed by the selected vet pass, -with failures reported through the ordinary check and publication flow. - -The option preserves current defaults for consumers that leave it unset. -ReleaseKit owns the offline command and its coordination with base testing. - -The API and profile now support replacing ConfigKit's and PromptKit's separate -vet commands and manual test-time vet settings with one declarative choice. - -## 5. Verify package compilation for selected targets - -### Rationale and baseline at plan start - -ReleaseKit's existing build declaration selects executable artifacts and their -delivery. ConfigKit is a source-only library that checks package compilation -for Linux amd64 and arm64. Its current release script owns the cross-target -build loop even though the underlying mechanics are shared across consumers. - -### Target end state - -The public API and profile can declare optional package-compilation targets -independently of executable artifacts. ReleaseKit compiles the module's packages -for those targets within candidate validation, after the selected test and vet -work. `Check` and `Publish` share this behavior and report compilation failures -through their existing outcomes. - -Package compilation uses the existing pure-Go build baseline (`CGO_ENABLED=0`). - -A source-only library retains page-only delivery. Package-compilation checks -require no binary name, version smoke command, or artifact manifest. Successful -compilation establishes build compatibility; execution on a target remains a -separate concern. Consumers select targets for their support commitments. - -The API and profile now let ConfigKit declare its two Linux targets and remove -its release-specific compilation loop when it adopts the selection. - -## 6. Check an optional expected publication endpoint - -### Rationale and baseline at plan start - -ReleaseKit resolves and captures the selected remote's push endpoint and -rechecks it during publication. ConfigKit additionally declares an expected -authoritative destination in its release script. Retaining that expectation -outside ReleaseKit would duplicate destination-resolution work. - -### Target end state - -An optional public API and profile setting declares the expected publication -destination. `Publish` compares it exactly with the effective push URL resolved -by Git before candidate validation and publication. A mismatch produces a clear -failure. -The existing captured-endpoint, recheck, and recovery machinery continues to -govern the operation. - -The expectation applies to the publication destination. Fetch configuration -retains its existing semantics, and `Check` retains its local-only behavior. -Consumers that omit the expectation keep the current remote-selection model. - -Consumers can now declare the intended push destination without maintaining -their own publication preflight logic. - -## 7. Offer Go formatting validation - -### Rationale and baseline at plan start - -PromptKit maintains a shell loop that enumerates tracked Go files and checks -their formatting. ReleaseKit currently leaves this generic mechanism to -consumer-owned additional checks. Shared support would remove that script -fragment and provide consistent diagnostics across applications. - -### Target end state - -An optional public API and profile selection enables formatting validation for -tracked Go source using ordinary `gofmt` conventions. `Check` and `Publish`, -including their CLI forms, apply the same check within candidate validation. -The check runs offline, reports affected paths, and leaves files unchanged. - -Consumers select the capability once and rely on ReleaseKit for enumeration, -format checking, and failure reporting. Existing validation defaults remain -unchanged when the option is unset. - -PromptKit can now remove its local formatting loop and select the shared check -through its release profile when it adopts the capability. - -## 8. Offer offline Markdown-link validation - -### Rationale and baseline at plan start - -PromptKit's largest generic validation block is a local Markdown-link checker. -It owns parsing, destination resolution, heading anchors, and diagnostics. -ReleaseKit currently leaves these mechanics to consumer-owned additional checks. - -Sharing the check would remove a locally maintained parser and give consumers -one documented convention for validating navigation within their documentation. -Consumers that require documentation to remain within the checkout also need -a shared option to enforce that boundary. - -### Target end state - -An optional public API and profile selection checks tracked Markdown documents -for local destinations and supported heading fragments within the checkout. -`Check` and `Publish`, including their CLI forms, use the same offline, -read-only validation and report the source file, location, and target of each -problem. - -ReleaseKit owns a documented link and heading-anchor convention that consumers -can follow, using PromptKit's current conventions as the starting specification. -The supported behavior accounts for common inline and reference links, code -examples, escaped destinations, and duplicate headings. External -website availability is outside the check's scope. - -By default, links outside the checkout are classified and reported as outside -the shared check's scope. An optional setting makes local destinations outside -the checkout a validation failure, using the same parser and diagnostics. -Boundary validation remains independent of neighboring checkout contents. -Existing validation defaults remain unchanged when the option is unset. - -PromptKit can now replace its local Markdown checker with a profile selection -and rely on shared parsing rules and diagnostics when it adopts the capability. - -## 9. Offer module-distribution checks - -### Rationale and baseline at plan start - -PromptKit checks that released source is independent of neighboring checkouts -by excluding committed workspace files and local filesystem module replacements. -ReleaseKit's offline Go environment controls validation execution; inspecting -the distributed candidate requires separate checks that consumers currently own. - -Shared inspection would remove these local checks and provide consistent -diagnostics for consumers with the same distribution requirements. - -### Target end state - -The public API and profile offer independently selectable rules for committed -workspace files (`go.work` and `go.work.sum`) and local filesystem replacements -in committed module declarations. Each selected rule reports offending paths -and, where applicable, module directives through shared candidate validation. - -The replacement rule permits versioned module replacements. Workspace use and -vendoring retain their existing behavior unless affected by a selected rule. -The checks inspect candidate contents independently of the Go test environment. -`Check` and `Publish`, including their CLI forms, apply the same offline, -read-only checks. Omitted selections preserve current defaults. - -PromptKit can now declare its distribution requirements and remove the -corresponding consumer-owned checks when it adopts the selections. - -## 10. Offer an individual-file-size check - -### Rationale and baseline at plan start - -Unintentionally committed binaries and large assets can increase the size of -released source. ReleaseKit currently leaves file-size inspection to consumers. -A shared check would catch oversized files while allowing each consumer to -declare its intended size limit and exceptions. - -### Target end state - -An optional public API and profile selection checks individual tracked files -in the current candidate. When enabled, the default limit is 1 MB (1,000,000 -bytes); consumers can configure the limit and explicit repository-relative -path exclusions for intentional large files. A file exceeding the limit fails -validation with its path, observed size, and configured limit. - -The check measures file size. Small binaries remain subject to ordinary review. -Its scope is the current candidate's files; historical objects and aggregate -repository size remain separate concerns. `Check` and `Publish`, including -their CLI forms, use the same offline, read-only inspection. The check is -disabled by default. - -Consumers can now catch oversized candidate files through a small declaration -and remove corresponding local inspection code when they adopt the check.