From b96262eb0ce9c8f2eb3e948a5841db2b799bc91b Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sat, 10 Oct 2026 15:44:03 +0000 Subject: [PATCH] Remove completed module release roadmaps and review notes --- docs/roadmap/commandkit-feature-request.md | 158 ---- docs/roadmap/implementation.md | 797 --------------------- docs/roadmap/module-releases.md | 335 --------- docs/roadmap/remediation.md | 587 --------------- examples/multi-module/README.md | 8 +- 5 files changed, 4 insertions(+), 1881 deletions(-) delete mode 100644 docs/roadmap/commandkit-feature-request.md delete mode 100644 docs/roadmap/implementation.md delete mode 100644 docs/roadmap/module-releases.md delete mode 100644 docs/roadmap/remediation.md diff --git a/docs/roadmap/commandkit-feature-request.md b/docs/roadmap/commandkit-feature-request.md deleted file mode 100644 index d0e8558..0000000 --- a/docs/roadmap/commandkit-feature-request.md +++ /dev/null @@ -1,158 +0,0 @@ -# CommandKit feature request: publish individual modules in a shared repository - -Status: requested upstream capability; not an implemented ReleaseKit contract. - -## Consumer context - -CommandKit uses ReleaseKit v0.3.0 for source-only publication. CommandKit is -still an unreleased prototype and is preparing to separate its core from -optional integrations into three independently versioned Go modules: - -| Repository directory | Module path | Illustrative version | Corresponding Git tag | -| --- | --- | --- | --- | -| Root | `gitea.maximumdirect.net/eric/CommandKit` | `v0.1.0` | `v0.1.0` | -| `integrations/ckconfig` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckconfig` | `v0.2.0` | `integrations/ckconfig/v0.2.0` | -| `integrations/ckprompt` | `gitea.maximumdirect.net/eric/CommandKit/integrations/ckprompt` | `v0.1.0` | `integrations/ckprompt/v0.1.0` | - -These versions illustrate independent numbering; they are not selected initial -release versions. Integration versions will describe their own changes rather -than matching either CommandKit core or upstream library versions. - -The dependency direction is `ckprompt` toward `ckconfig` and core, and -`ckconfig` toward core. Consumers should acquire only their selected integrations -and their dependencies. Each integration therefore needs its own module files, -validation, release notes, and publication identity. More integration modules may -follow without requiring a new publication mechanism for each one. - -Go requires repository-subdirectory prefixes on nested module version tags. -The semantic module version remains `vMAJOR.MINOR.PATCH`; the complete Git tag -additionally identifies the module directory. See the -[Go module reference](https://go.dev/ref/mod#vcs-version). - -## Issue with the current publication contract - -ReleaseKit's documented [CLI](../cli.md), [profile](../config.md), and -[publication API](../consumers/publish.md) assume one release version/tag and -one standard Go suite. Release notes use repository-root -`docs/releases/.md`, and publication accepts stable -`vMAJOR.MINOR.PATCH` rather than a nested module's prefixed tag. - -Changing the product name or choosing another profile does not provide a -separate module directory, semantic version, and Git tag identity. Running the -root module's suite also does not validate packages belonging to nested modules. - -CommandKit would otherwise need to implement its own integration publication -path, duplicating functionality already owned by ReleaseKit. We would prefer -ReleaseKit to support selecting one Go module within the shared repository. - -## Requested feature - -Support checking and publishing one explicitly selected module per invocation, -through the public library API and native CLI/profile interface. The request is -about observable behavior; ReleaseKit should select its own internal design. - -### Repository and module selection - -- Distinguish the Git repository from the selected module's directory within it. -- Keep repository state, candidate commit, branch, remote, and publication guards - scoped to the shared repository. -- Execute the standard Go validation suite in the selected module. Its tests, - and any selected module-specific vet or package compilation, should operate on - that module rather than implicitly validating only the repository-root module. -- Preserve ordinary root-module publication when no nested module is selected. -- Permit a shared repository launcher to choose small per-module profiles without - requiring separate Git repositories or duplicated publication logic. - -### Version and tag identity - -- Accept the selected module's semantic version separately from its repository - subdirectory, deriving the corresponding Go module tag from those inputs. -- Use the complete tag for uniqueness checks, tag creation, publication, and - failed or ambiguous publication recovery. -- Make both module version and complete tag identifiable in public results and - CLI output, alongside the candidate commit and existing publication evidence. -- Allow modules to publish different versions and to release individually. - Equal semantic versions in different modules identify different tags. - -No arbitrary tag-template language is needed by CommandKit. Standard Go module -tag conventions meet its requirements. - -### Release notes - -Support a distinct committed note for each module release, even when two modules -use the same semantic version. CommandKit's preferred layout is module-local -`docs/releases/.md`, for example: - -```text -docs/releases/v0.1.0.md -integrations/ckconfig/docs/releases/v0.2.0.md -integrations/ckprompt/docs/releases/v0.1.0.md -``` - -Validate the selected note against its product and semantic version in the -captured candidate. The complete tag remains the immutable source identity for -note links, licensing links, and publication recovery. A documented explicit -note-path setting would also be acceptable if module-local discovery is not the -selected public design. - -Document how module version, complete tag, note title, and note location relate; -align affected release-policy language with the selected conventions rather than -treating the current single-module note path as an obstacle. - -### Validation and completion - -Run the selected module's standard suite once for the publication candidate, -retaining ReleaseKit's offline validation and existing publication outcome model. -Additional product checks may cover CommandKit-specific composition or dependency -boundaries without repeating the selected standard suite. - -CommandKit will prepare dependencies before offline validation. Its published -modules will require actual released dependency versions; local workspace -composition is useful during development but does not establish ordinary consumer -resolution. For releases requiring new sibling versions, CommandKit can publish -core, then `ckconfig`, then `ckprompt`, preparing each candidate as needed. - -Successful source-tag publication should remain the completion point. This -request does not add CI polling, hosted release pages, artifact delivery, module -proxy availability, or consumer installation as publication completion gates. - -## Illustrative consumer interface - -Conceptually, a request would supply: - -```text -Repository: /work/CommandKit -Module directory: integrations/ckconfig -Product: CommandKit ConfigKit integration -Module version: v0.2.0 -``` - -ReleaseKit would select that module's suite and committed note, and publish -`integrations/ckconfig/v0.2.0` for the captured repository candidate. Exact Go -field names, CLI options, and profile syntax remain ReleaseKit design choices. -CommandKit could then expose a small convenience launcher such as -`./scripts/release ckconfig v0.2.0`; that is illustrative consumer syntax, not a -request for ReleaseKit to hard-code CommandKit's module names. - -## Acceptance scenarios - -1. Publish the root module using ordinary unprefixed tags and existing defaults. -2. Publish either nested integration with its Go-required prefixed tag and its - own committed note, without publishing unrelated module tags. -3. Identify validation failures from the selected nested module and prevent its - publication, even if the root suite would pass. -4. Publish two modules using the same semantic version without note or tag - collisions; preserve existing guards against reusing a published full tag. -5. Report the complete selected tag in known-failure or unresolved-publication - results so recovery addresses the exact destination and tag object. - -## Follow-up possibilities - -Publishing an explicit set of independently versioned modules in one operation -could later reduce repeated repository checks and support coordinated releases. -Batch or atomic multi-tag publication is not needed for this initial request. -Neither are automatic module discovery, dependency-driven version selection, -matching version numbers, or a generic release-orchestration framework. - -CommandKit can adopt single-module selection first and revisit release sets when -concrete maintenance needs justify them. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index 91a4bf7..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,797 +0,0 @@ -# Implementation plan: individual Go module releases - -Status: complete; all 15 stages implemented and locally verified. - -The subsequent [remediation review](remediation.md) records post-implementation -findings, corrections, and their verification. The baseline and stage accounts -below retain the implementation sequence. - -## Objective and authority - -Implement the complete target in the [module-release roadmap](module-releases.md), -including its resolved decisions, and [ADR 0005](../adr/0005-module-release-scope.md). -The [CommandKit request](commandkit-feature-request.md) supplies consumer context. -The implementation covers checking, publication, standalone and composite builds, -prebuilt receipts, hosted delivery, CLI profiles, launchers, and Woodpecker. - -This document is an ordered implementation guide for a Luna coding agent. -Complete Stage 1 through Stage 15 in order. Each stage is a focused implementation -unit with its own behavioral verification. Intermediate stages represent partial -implementation; completion means that all stages are complete. Proceed through -the plan without pilot integrations, intermediate releases, external actions, or -human review gates. Architecture review and subsequent adoption testing follow -completion of this plan. - -Read [development](../development.md) and the applicable policies before working. -Use the codebase graph for code discovery and inspect the current source before -editing. Follow the [agent policy](../policy/agents.md) for scoped commits after -completed nonempty units. Record completion under each stage with a short account -of the change and verification. Keep behavior documentation aligned as each -capability lands; the feature roadmap owns the desired scope and policy choices. - -## Baseline and implementation boundaries - -The starting point is the v0.3.0 implementation with accepted module-release -decisions. Current entry points are the root facade's `Check`, `Publish`, `Build`, -`Deliver`, `PrepareTaggedCheckout`, and `PrepareBuildDependencies`. - -| Current owner | Change needed | -| --- | --- | -| `check.go`, `publish.go`, `build.go`, `delivery.go`, `preparation.go` | Facade-owned selection and evidence types, explicit conversions. | -| `internal/candidate`, `internal/publish` | Committed module identity, module-local notes, full-tag publication and recovery. | -| `internal/validation` | One selected input set, full repository reference lookup, selected-module Go execution. | -| `internal/git`, `internal/preparation` | Literal full-tag operations and shared tagged-source verification. | -| `internal/gotool`, `internal/build`, `internal/artifact` | Operation-local Go settings, normalized build settings, module-based execution and output. | -| `internal/delivery`, `internal/gitea` | Committed delivery identity, module-bound artifacts, full-tag hosted identity. | -| `cmd/releasekit`, `cmd/releasekit/internal/cli` | Profile mapping, command context, receipts, CI event handling. | -| `examples/woodpecker/`, consumer guides | Root defaults and module-selected bootstrap from tagged source. | -| `internal/apicheck` | Compiled facade ownership and dependency checks for the current API. | - -Keep implementation behind the existing facades. `buildinfo` keeps its small -independent runtime dependency graph. Use the existing pure-Go build baseline, -standard version injection, target rules, error causes, publication outcomes, -and delivery recovery behavior. Network-capable preparation remains separate -from offline validation and compilation. - -The feature is a clean API and receipt cutover. Update callers and fixtures to -the current interface directly. Migration is documentation for the next release. -Implement individual module releases without batch publication, automatic module -discovery, dependency ordering, arbitrary tag templates, or compatibility shims. - -## Concrete interface and ownership choices - -These choices settle routine design details needed to execute the stages. GoDoc -and canonical references become their owners when the corresponding code lands. - -### Selection and evidence - -- Add `ModuleDir string` to `ReleaseRequest`, `BuildRequest`, and - `DeliveryRequest`. Input values are repository-relative; omission or `.` selects - the repository-root module. Keep `Version` as the stable semantic version. -- Add `ModuleDir`, `ModulePath`, and `Tag` to `Candidate`, `PublicationResult`, - `BuildResult`, and `DeliveryResult`. Result `ModuleDir` is the resolved absolute - execution directory; `ModulePath` is the declared import path; `Tag` is the - complete derived Git tag. Retain existing repository, commit, and outcome - fields, adding `RepositoryDir` to results that currently lack it. -- Use one private identity value in `internal/releaseidentity`, containing the - absolute repository and module directories, canonical repository-relative - module subdirectory, declared module path, semantic version, complete tag, and - repository-relative note path. Source commit remains captured operation - evidence. Facades own their exported types and explicitly convert this value. -- Add `SharedFiles []string` to `ValidationSpec`. Profile syntax is - `validation.shared_files`; profile module selection is top-level `module_dir`. - Preserve nil versus non-nil empty slices through all conversions and JSON - round trips. Existing `--config` selects the profile; the initial CLI adds no - separate module override. -- Change `PrepareBuildDependencies` to accept a facade-owned - `DependencyPreparationRequest` containing `RepositoryDir` and `ModuleDir`. - Preparation selects the working-tree module directory and performs the - existing network-capable preparation there. It needs no release version or tag. -- Replace `TaggedCheckoutRequest.Version` with `Tag`. Add `VerifyOnly bool`: - the default prepares the checkout, while `true` performs read-only verification - of an already prepared checkout against `Tag` and `ExpectedCommit`. -- Add optional `DeliveryRequest.ExpectedTag` for the CI event's literal tag. - Delivery compares it with the resolved tag before builds or hosted requests. - Ordinary callers omit it. The field expresses exact event identity. - -Identity derivation is shared; operation prerequisites remain with their owners. -Check and publication read declarations from the captured commit. Delivery reads -committed declarations from its source checkout and verifies the derived tag. -Standalone builds read working-tree declarations. Composite builds receive the -owner's already resolved identity. Populate evidence as it becomes available, -including on errors; an unresolved field remains unset. - -### CLI events, receipts, and consumer mapping - -- `check`, `publish`, `build`, and ordinary `deliver` continue to accept a - semantic `VERSION`. `ci-deliver` accepts a complete `TAG`; its last path - component supplies the semantic version and its full value supplies - `ExpectedTag`. The selected profile supplies the physical module directory. -- Add `ci-deliver --prepared` to select `VerifyOnly`. The maintained workflows - use it after bootstrap's verified checkout. Standalone `ci-deliver` retains - checkout preparation by default. Both paths require `--commit` and perform - fresh read-only tag, HEAD, cleanliness, and expected-commit checks. -- Add optional `--expected-module DIR` to `publish` and `ci-deliver` for mapped - launchers. Compare its normalized repository-relative selection with the - profile's selection before application work. This equality expectation binds - the bootstrap module to the profile; module selection still comes from the - profile. Root-only invocations omit it. -- Keep `.releasekit-build.json` as the private receipt filename. The new schema - requires `schema_version: 1`, absolute `module_dir`, declared `module_path`, - and complete `tag`, alongside the existing fields. The current unversioned - receipt is rejected with regeneration guidance. Implement one schema reader. -- For the maintained multi-module example, use a small committed - `release-modules.tsv` shared by the launcher and CI. Each row contains four - tab-separated fields: selector, event-tag shell pattern, repository-relative - physical module directory, repository-relative profile path. Use `.` for root. - A shared POSIX shell helper reads the table for either a selector or an event - tag. An event must match exactly one row; ambiguity is a selection error. - Tag patterns select a row; the library remains the authority for tag derivation. - The maintained example owns this integration declaration. - Root-only consumers continue without a mapping file or helper. - -For example, root v0/v1 and root `v2` directory layouts can use separate rows -with patterns `v[01].*` and `v2.*`. A nested `/v2` module can map -`integrations/ckconfig/v2.*` to either physical layout. Keep patterns quoted and -evaluate them as shell patterns without `eval`. Document the table's literal -tab-separated syntax. No matching pattern changes the derived release tag. - -## Stage 1: Implement shared identity derivation and literal tag operations - -**Outcome:** One internal owner derives release identity for both source modes; -Git primitives accept full tag names independently of semantic-version rules. - -**Steps:** - -1. Introduce `internal/releaseidentity` with a selection resolver and shared pure - derivation. Resolve module paths once from repository-relative input, with - ordinary normalization and a final location inside the repository. Keep root - defaults. Require the selected module's own declaration; do not silently - fall back to an ancestor module or require a repository-root `go.mod` for a - nested selection. -2. Provide committed and working-tree declaration readers. Reuse existing Git - committed-file and reference resolution where needed. Preserve cause and - cancellation handling. Do not fetch module metadata or infer identity from - the remote host, a root module declaration, or a directory-name registry. -3. Extract the module directive with the existing `modfile.ModulePath` helper - and apply `module.SplitPathVersion`/`module.CheckPathMajor`. Full `go.mod` - inspection retains its selected validation owner. Retain stable-version - syntax and use the shared module-path major-version rules. - Derive the tag prefix from the physical repository-relative directory, - removing a final physical major-version component only when it equals the - declaration's slash major suffix. Distinguish a normal directory named `v2` - from a physical `/v2` layout using the declaration. Retain standard special - path-major handling supplied by `x/mod`. -4. Derive `/docs/releases/.md` from the physical directory, - including a physical major-version directory. Keep tag prefix and note path - as distinct values. The - [Go module reference](https://go.dev/ref/mod#vcs-version) and - [path-major helpers](https://pkg.go.dev/golang.org/x/mod/module#CheckPathMajor) - define the relevant Go rules. -5. Replace Git's version-shaped tag validation with literal tag-reference - validation using Git's reference rules. Rename parameters and internal - fields that actually represent tags. Preserve exact ref/object operations, - supported tag object types, and repository-state checks. Semantic-version - validation stays at release identity boundaries. - -**Verification:** Owner tests cover root, nested, root physical `v2`, nested -physical `v2`, `/v2` declarations without physical major directories, a normal -directory named `v2`, incompatible version majors, normalized selection, missing -or malformed declarations, and selection outside the repository. Test committed -versus working-tree readers and full slash-containing Git refs. Update synthetic -fixtures that need genuine module declarations. Run affected package tests. - -**Completed:** Added shared committed and working-tree module identity derivation, -module-local note paths, and literal Git tag-reference validation. Verified root, -nested, physical-major, and ordinary `v2` layouts, committed versus working-tree -declarations, and slash-containing local and remote tag operations. `go test ./...` -passes. - -## Stage 2: Carry identity through facade types and candidate capture - -**Outcome:** Candidate capture supplies module-local notes and recoverable identity -through the public facade. - -**Steps:** - -1. Add the selection and evidence fields specified above to facade-owned types - and their internal counterparts. Use focused conversion helpers where they - remove repeated evidence construction. Preserve `errors.Is`/`errors.As` - behavior and existing callback signatures using facade-owned `Candidate`. -2. In `internal/candidate.Capture`, capture repository state and commit, resolve - committed identity once, then read the selected module's committed note and - apply existing product/version title validation. Use the full tag for the - local unused-tag guard. -3. Return progressively populated candidate evidence when later capture, - validation, or recheck work fails. Update the public `Check` conversion so - it preserves returned evidence alongside the error instead of replacing it - with an empty candidate. -4. Pass identity through candidate validation and post-validation callbacks. - Keep clean `main`, repository-wide status, capture/recheck behavior, and note - bytes with their current owners. Prepare internal request wiring for later - validation and build stages without adding alternate legacy paths. -5. Update compiled API checks and fixtures for the chosen facade declarations. - Keep internal identity types out of exported signatures and fields. - -**Verification:** Root notes retain their path and title. A nested candidate uses -its own note, including a physical major directory. Note/title/tag conflicts and -later validation failures retain available module, version, tag, and commit -evidence. An unrelated sibling worktree change still fails the repository guard. -Run candidate/facade tests and `go run ./internal/apicheck`. - -**Completed:** Added module selection and identity evidence to the facade and -internal request/result types. Candidate capture now reads the selected -committed declaration and module-local note, guards the complete local tag, and -preserves available evidence through callbacks and later failures. Verified -nested physical-major capture, sibling cleanliness, facade error evidence, -`go test . ./internal/candidate`, and `go run ./internal/apicheck`. - -## Stage 3: Publish and reconcile the complete selected tag - -**Outcome:** Publication addresses one module's exact tag and retains its current -known-failure, confirmed, and unknown outcomes. - -**Steps:** - -1. Thread captured identity through `internal/publish`; use `Tag` for remote - uniqueness, annotated-tag creation, exact-object push, and reconciliation. - Continue using `Version` for product/version messages where it is semantic. -2. Preserve the authoritative endpoint, expected push URL comparison, remote - branch/commit guards, local rechecks, bounded reconciliation, and tag object - evidence. These checks verify state against the captured identity and do not - invoke identity derivation again. -3. Populate `PublicationResult` identity before later failures and preserve it - through facade conversions. Recovery output identifies the full tag and - authoritative endpoint rather than constructing a ref from the version. - -**Verification:** Publish two modules with the same version at the same captured -commit to a temporary local remote; only their separate intended tags appear. -Reject reuse of the full tag. Add representative nested-tag rejected-push and -unknown-outcome evidence cases. Reuse existing endpoint and lost-acknowledgment -tests for unchanged recovery mechanics. Run publication and Git tests. - -**Completed:** Publication now uses the captured full tag for remote uniqueness, -local annotated-tag creation, exact-object push, and reconciliation. Recovery -errors identify the full tag and authoritative endpoint, while publication -results retain identity through preflight and later failures. Verified two -modules publishing the same version at one commit, full-tag reuse rejection, -nested rejected and unknown outcomes, and `go test . ./internal/git ./internal/publish`. - -## Stage 4: Construct the selected committed file inputs - -**Outcome:** One ordered path set defines automatic validation inputs, while the -full committed repository remains available for reference lookup. - -**Steps:** - -1. Add scope selection beside `CandidateTree` metadata handling. Select entries - beneath the module directory, excluding descendants belonging to nested - committed `go.mod` boundaries. Boundary detection uses locations and does - not parse unrelated declarations. Treat vendored contents as selected-module - material; vendored `go.mod` entries do not establish exclusion boundaries. -2. Preserve the complete repository index and committed resolver separately. - Add a selected-input view used by checks; avoid replacing the complete tree - with a filtered map that breaks cross-module links or committed symlinks. -3. Resolve `SharedFiles` once against committed entries. Apply the roadmap's - optional defaults, replacement list, explicit empty list, missing-explicit - errors, and explicit cross-module file selection. Literal paths identify - individual files; metacharacters have no selection semantics. Retain existing - symlink/reference behavior where applicable. -4. Merge selected module entries and shared files in stable repository-path - order, deduplicating by committed path. Preserve per-path context when - different paths share a blob. A referenced destination joins the input set - only through independent module or explicit-file selection. -5. Create inputs only when enabled file checks or explicit shared-file validation - require them. An explicit missing file fails even with all file checks off; - a default-only request with no file checks needs no file-input construction. - Keep lazy blob access, operation context, cancellation, and reader cleanup. - -**Verification:** Scope tests cover root and nested modules, independent sibling -and nested fixture modules, vendor inclusion, optional defaults, replacement, -empty, missing explicit, duplicates, and selected files in another module. -Use committed files rather than worktree presence. Show that full lookup still -resolves an excluded module's destination. Metadata-only selection starts no -batch content reader. Run validation tree/scope tests. - -**Completed:** Added a sorted, deduplicated committed input view for the selected -module and explicit shared files while retaining full-tree reference lookup. -Nested module boundaries exclude their descendants, vendored modules remain -included, and shared-file defaults, replacement, empty selection, and missing -committed files follow the roadmap. Verified root and nested scopes, worktree-only -file rejection, cross-module references, lazy content reads, `go test ./internal/validation ./internal/candidate .`, -and `go run ./internal/apicheck`. - -## Stage 5: Apply selected inputs to every optional file check - -**Outcome:** Formatting, workspace, local replacement, file-size, and Markdown -checks use the same selected inputs with their existing individual rules. - -**Steps:** - -1. Update checker iteration to consume the selected-input view from Stage 4. - Retain the full repository resolver for targeted source and destination reads. - An unrelated sibling declaration or root workspace file outside a nested - module's inputs does not independently fail that module's check. -2. Translate module-relative file-size exclusions once into canonical - repository-relative paths before checker execution. Preserve existing literal - file/directory exclusion matching, limits, findings, and check order. -3. Retain formatter selection, symlink treatment, committed replacement - inspection, Markdown syntax and fragment rules, boundary observations, - source locations, cause propagation, and the existing per-blob caches. - Diagnostics remain repository-relative; Markdown links remain relative to - each source document. -4. Keep content-reader cleanup attributed to the last check that actually read - content. Do not reintroduce full raw-content retention or per-check tree - scans merely to carry module scope. -5. Give explicit shared-file selection errors a public validation identity - `shared-files`, with the selected repository-relative path and cause. Add its - facade conversion and CLI presentation through the existing failure model. - Shared-file selection itself enables no content check. - -**Verification:** Place real violations inside and outside selection and show -that only in-scope inputs fail each selected checker. Cover shared files under -enabled checks, module-relative exclusions, and a cross-module Markdown heading -read that leaves unrelated destination documents unchecked. Equal Markdown blobs -at different paths keep distinct relative-link findings. Confirm selection -errors with content checks disabled and preserve cancellation/cleanup regressions. -Run affected validation and facade tests. - -**Completed:** Formatting, workspace, local-replacement, file-size, and Markdown -checks now iterate the selected committed inputs. Targeted reads still resolve -against the full repository tree. File-size exclusions are translated from the -selected module to repository-relative paths, and shared-file failures preserve -their public check, path, and cause. Updated file-size guidance and verified -in-scope and out-of-scope findings, shared inputs, cross-module anchors, reader -cleanup, facade conversion, `go test ./internal/validation .`, and -`go run ./internal/apicheck`. - -## Stage 6: Execute Go validation in the module with reusable local settings - -**Outcome:** One selected standard suite runs in the module, and later composite -builds can reuse its effective Go environment. - -**Steps:** - -1. Change validation Go command directories to resolved `ModuleDir`. Preserve - offline, readonly, workspace-disabled behavior and selected race, full vet, - target compilation, output, and command ordering. -2. Introduce a small operation-local lazy Go-tool owner alongside the existing - `gotool.Tool`. Candidate validation and subsequent build callbacks share it; - delivery and standalone builds own separate instances. It acquires settings - only when a Go command needs them. -3. Reuse the discovered tool while effective environment inputs are unchanged. - Retain a snapshot of inherited environment and the persistent Go settings - source used for discovery; after consumer callbacks, compare those inputs - and rediscover if they changed. Use simple value/file comparisons within - this owner. Keep preparation's network-capable settings separate. Introduce - neither a public session object nor a process-global tool cache. -4. Pass the private owner through internal candidate/build coordination. Preserve - repository-wide state rechecks and the single shared validation invocation. - -**Verification:** A failing nested test suite prevents its release while root -tests pass. An unrelated sibling failing suite does not run. Selected vet and -compile targets use the same module and existing baseline. Observe one standard -suite and reused discovery in an unchanged validation/build operation; changing -environment inputs through an additional callback triggers fresh settings. -Run Go-tool, validation, and candidate coordination tests. - -**Completed:** Go validation commands now run from the captured module -directory. Candidate checks and publication share a lazy operation-local Go -settings owner with their later build callbacks; standalone and managed delivery -builds acquire separate owners. The owner reuses discovery while the inherited -environment and selected `GOENV` file stay unchanged, and refreshes after -consumer callbacks when either changes. Nested-module fixtures now include -packages for selected-module validation. Verified one suite and shared discovery -through candidate build coordination, environment and persistent-file refresh, -nested-suite failure and sibling isolation, selected vet/compile command -directories and compile baseline, `go test ./...`, and -`go run ./internal/apicheck`. - -## Stage 7: Build the selected module and bind output evidence - -**Outcome:** Standalone and composite builds use the correct declaration source, -version injection, path base, and identity. - -**Steps:** - -1. Make public standalone `Build` resolve working-tree identity once, then call - an internal build path that consumes resolved identity. Candidate and managed - delivery builds call that path with committed identity and their Go-tool - owner. They do not call standalone resolution as a nested operation. -2. Consolidate normalized build settings in `internal/artifact`, including main - package, binary name, and normalized target pairs. Reuse this representation - for execution, evidence, later receipt binding, and settings comparisons. - Preserve supported target and artifact-name rules. -3. Build main packages from `ModuleDir`; resolve relative ordinary output there, - with default `/dist`. Keep absolute output usable. Candidate and - managed delivery output, including disposable native smoke output, stays - outside the entire repository through the existing temporary-directory owner. -4. Use semantic `Version` for linker injection, filenames, and exact native - version checks. Populate build identity before later errors and retain partial - artifacts, produced-byte digests, compiler evidence, and source observations. - An empty target set performs no compiler or Go-environment discovery. -5. Preserve standalone modified-source support and existing `SourceVerified` - observations. A build does not require a note, unused tag, clean `main`, or - publication. Delivery still requires verified committed tagged source. - -**Verification:** Build and run a nested native consumer using `buildinfo` and -cross-compile one supported second target. Filenames and output contain the -semantic version and retain ordinary filename components. Cover dirty declaration -changes and a new uncommitted module directory for standalone builds, committed -identity for composites, empty targets, and partial failures. Confirm temporary output is -outside the repository even with a nested selection and source-local `TMPDIR`. -Run build and runtime-boundary tests. - -**Completed:** Standalone builds now resolve working-tree module identity once; -candidate and managed delivery builds consume their committed identity and Go -tool owner through the resolved build path. Normalized build settings are shared -by execution and delivery evidence. Builds run from `ModuleDir`, use module-based -output paths, and keep temporary native smoke output outside the repository. -Verified nested native version output, a second cross target, dirty declarations, -new uncommitted nested modules, empty targets, temporary-output fallback and -cleanup, full `go test ./...`, `go run ./internal/apicheck`, and `git diff --check`. - -## Stage 8: Deliver module-local notes and assets to full-tag pages - -**Outcome:** Page-only, managed-build, and API prebuilt delivery share committed -module identity and existing recovery behavior. - -**Steps:** - -1. Capture checkout commit and resolve committed identity once in delivery; - inspect the derived literal tag against that checkout. Compare optional - `ExpectedTag`. Keep historical lightweight tags, detached checkouts, clean - source, and the existing post-build source recheck. -2. Read and validate the module-local committed note. Populate delivery evidence - as resolution progresses, including build and hosted failures. Use Stage 7's - resolved build path for managed builds. -3. Bind prebuilt results to repository, module directory, declared module path, - version, tag, commit, and existing artifact/settings evidence. Require - `SourceVerified` for binary delivery and preserve caller ownership of files. -4. Give Gitea requests a distinct full-tag field; stop applying stable-version - syntax to that field. Use the literal tag for hosted tag lookup, release - lookup/create, and conflicts. Titles remain from the version-bearing note. - Encode tags at HTTP/source-route owners and verify escaped slash behavior. -5. Preserve one local digest-and-size verification before hosted requests, - deterministic manifests, remote exact comparisons, additive retries, and - existing failure states. Page-only delivery performs no application build, - Go environment discovery, application download, receipt, or manifest work. - -**Verification:** Local HTTP fixtures receive correctly encoded nested tags and -their semantic-version note titles. Two module tags at one commit create -separate pages. Cover nested managed builds and reject an API prebuilt result -for another module before hosted requests. Reuse established tampering, conflict, -partial/unknown, historical-tag, and cleanup tests. Run delivery/Gitea tests. - -**Completed:** Delivery now captures checkout identity once, derives the -selected module's committed tag and note path, compares an optional expected -full tag, and returns module evidence through local and hosted failures. Managed -and prebuilt binary results bind to the same repository, module, version, tag, -commit, settings, and source verification; the CLI carries that identity through -its existing private receipt. Gitea uses the literal full tag and escapes -slashes in hosted routes. Verified two module pages at one commit, nested notes -and slash tags, mismatched expected tags and prebuilt identities, preserved -delivery recovery cases, `go test ./...`, `go run ./internal/apicheck`, and -`git diff --check`. - -## Stage 9: Replace receipts with the module-bound schema - -**Outcome:** CLI prebuilt delivery uses one current receipt format and one -delivery-owned content verification pass. - -**Steps:** - -1. Implement the schema specified above in CLI receipt read/write and public - build conversions. Keep the existing private filename and write/partial-build - lifecycle. Require all identity fields, even for a root build. -2. Validate the schema version, field structure, source identity relationships, - normalized settings, artifact declarations, and receipt/output location. - Check internal tag/module/version consistency through shared pure derivation - using recorded identity, without resolving a new operation's source. -3. Reject old/unversioned or unknown-schema receipts with guidance to regenerate - through the updated build command. Do not migrate or accept their old shape. -4. Remove artifact content hashing from receipt loading and adjacent prebuilt - declaration/comparison work. Loading validates declared paths and digests; - Stage 8 delivery verifies actual bytes and sizes before any hosted request. - Build-time hashing records produced bytes independently. -5. Reuse normalized settings in profile-to-receipt comparisons. Keep structural - validation distinct from source verification and actual asset verification. - -**Verification:** Round-trip a root and nested receipt. Reject old schema, -malformed identity, and mismatched module or settings. A loaded receipt with -changed or missing artifact bytes fails during delivery before hosted requests. -Protect verification ownership through an observable read boundary rather than -tests tied to private helper choreography. Run receipt and CLI prebuilt tests. - -**Completed:** Replaced the unversioned receipt with schema version 1 and pure -recorded-identity checks for module path, physical directory, version, and full -tag. Receipt loading now validates structure and normalized settings without -opening artifacts; delivery remains responsible for verifying artifact bytes -and sizes before hosted requests. Old and unknown schemas require regeneration. -Verified root and nested receipts, malformed identity and settings, changed and -missing artifacts, `go test ./...`, `go run ./internal/apicheck`, and -`git diff --check`. - -## Stage 10: Map profiles and product commands to module operations - -**Outcome:** Local check, publication, and build commands express the new API with -small profiles and module context. - -**Steps:** - -1. Add strict profile decoding and mapping for `module_dir` and - `validation.shared_files`. Omission/null versus explicit empty selections - survive loading, copying, serialization, and facade mapping. Do not use - `omitempty` serialization that collapses explicit empty shared-file lists. -2. Keep profile lookup relative to the repository, including `--config`, and - pass module-relative owned paths to the common normalization boundary. Avoid - resolving identity a second time in CLI mapping. -3. Run configured product commands with `Candidate.ModuleDir` as CWD. Keep - existing version/commit context and add `RELEASEKIT_REPOSITORY_DIR`, - `RELEASEKIT_MODULE_DIR`, `RELEASEKIT_MODULE_PATH`, and `RELEASEKIT_TAG`. - Supply captured context without modifying the parent process environment. -4. Update check/publication/build diagnostics and recovery text to identify module, - semantic version, and full tag as available. Preserve existing native exit - classifications and presentation of underlying validation failures. - Implement `publish --expected-module` as a profile-selection comparison using - the shared path normalization, without another declaration resolution. -5. Apply the dependency preparation request cutover and its facade conversions. - Preparation resolves selection without release-note or publication prerequisites. - -**Verification:** CLI profiles select root/nested API requests; explicit empty -lists survive round trips. Product commands observe module CWD and both contexts. -Relative profile lookup remains repository-based and build output module-based. -Missing explicit files fail without enabling checks. Verify nested failure -diagnostics and retain a minimal root profile with no new required fields. -Run CLI profile, command, preparation, and compiled API checks. - -**Completed:** Profiles now map `module_dir` and `validation.shared_files`, -preserving nil versus explicit empty selections through JSON and facade copies. -Candidate commands run from the selected module with repository, module, path, -version, commit, and full-tag context. `publish --expected-module` compares -normalized profile selection before callbacks, and delivery/build map the profile -module through their facades. Dependency preparation now accepts a -repository/module request and runs in that module. Verified nested CLI checks and -build selection, explicit missing shared files, mismatch rejection before -product commands, module-targeted preparation, `go test ./...`, -`go run ./internal/apicheck`, and documentation whitespace checks. - -## Stage 11: Implement full-tag CI delivery and prepared-checkout verification - -**Outcome:** The CLI can prepare a complete event tag or reuse a verified -bootstrap checkout, then deliver the selected module. - -**Steps:** - -1. Update `ci-deliver` parsing to accept full `TAG`, required expected commit, - and optional `--prepared`. Validate literal ref syntax and stable terminal - version separately; ordinary commands still accept semantic versions. -2. Implement `TaggedCheckoutRequest.Tag` and `VerifyOnly` in preparation. Share - read-only verification between both modes; default preparation fetches the - exact tag and detaches its expected commit, then verifies. Verify-only checks - matching tag, HEAD, clean repository, and expected commit without fetch or - checkout. Preserve default remote selection and existing failure causes. -3. Load the profile from the prepared source using repository-based path rules. - Compare optional `--expected-module` with its normalized selection before - application dependency preparation; mismatch is a profile-selection error. - Pass its module selection, parsed semantic version, and event `ExpectedTag` - into delivery. Delivery owns committed identity resolution and exact mapping - verification. Keep ordinary `deliver` free of checkout/download preparation. -4. Prepare application dependencies in the selected module only for binary - profiles. Continue reading delivery credentials only for delivery; preparation - and configuration failures retain their existing CLI classifications. -5. Update prebuilt CLI delivery to compare the new receipt and normalized profile - settings, then delegate actual source/asset validation to the facade. - -**Verification:** Standalone CI delivery prepares a nested event tag. Prepared -mode succeeds offline without repeat fetch or checkout and rejects wrong commit, -dirty source, missing/moved tag, and inconsistent profile module. Verify detached -historical delivery, module-targeted dependencies for binaries, and page-only -application-preparation omission. Run preparation and CLI delivery tests. - -**Completed:** CI delivery now accepts literal full tags and derives the stable -semantic version from the final path component. Tagged checkout preparation -shares read-only tag, HEAD, expected-commit, and cleanliness verification with -the offline `--prepared` mode. CI profiles load from that checkout, optional -`--expected-module` is compared before application dependency preparation, and -the event tag is passed through delivery for exact identity checks. Binary -dependency preparation remains module-targeted and page-only profiles skip it. -Verified nested tag preparation, prepared CLI delivery without a remote, wrong -commit and dirty/missing/moved tag rejection, profile parsing, full `go test -./...`, `go run ./internal/apicheck`, and `git diff --check`. - -## Stage 12: Preserve the small root-module workflow - -**Outcome:** Existing root-only consumers retain a small launcher, profile, and -module-selected CI bootstrap under the current interface. - -**Steps:** - -1. Update `examples/woodpecker/tag-delivery.yml` and the self-bootstrap source - example to use prepared CI delivery after exact event checkout verification. - Keep root module files and default root profile selection. -2. Retain temporary alternate module metadata outside the repository, tagged-source - tool selection, workspace/toolchain controls, compatible Go image selection, - and credential handling. Tool bootstrap's network access remains separate - from offline application compilation. -3. Keep ReleaseKit's own `scripts/release`, root profile, and maintainer procedure - consistent where affected. Root consumers need no module map, extra required - configuration, or additional routine decisions. -4. Update root workflow tests for the receipt/API cutover and prepared mode. - Reuse existing synthetic tool modules and isolated module cache helpers. - -**Verification:** Execute the root launcher/API/profile representative flows and -both maintained root workflow harnesses. Bootstrap and retry select tooling from -the original tagged module after the default branch changes. Confirm subsequent -delivery performs read-only checks without repeating checkout preparation. -Use local remotes/proxies and temporary `GOMODCACHE`, never live CI or credentials. - -**Completed:** Both maintained root Woodpecker templates now verify and detach -the exact event tag before invoking `ci-deliver --prepared`, so delivery repeats -the source checks without fetching or changing checkout state. Updated workflow -tests assert the prepared flag while retaining local proxy coverage for the -tagged ReleaseKit selection, self-bootstrap, retry behavior, and source-only and -binary delivery. Verified the root profile and compiled API boundaries, the -maintained workflow harnesses, `go test ./...`, and `git diff --check`. - -## Stage 13: Add a shared multi-module declaration and local launcher example - -**Outcome:** Consumers select modules through small declarations with one maintained -helper shared by local release commands and CI. - -**Steps:** - -1. Add `examples/multi-module/` with root and integration profiles, the specified - TSV mapping, and POSIX shell selection helper. Include a physical-major - directory selection to demonstrate the distinction between module and tag. -2. Have the helper select by local selector or full event tag and return the - physical directory/profile. Share parsing and selection rather than copying - cases into separate launcher and workflow code. Keep unknown selectors and - ambiguous events as configuration errors. -3. Add a small shared launcher that chooses the row, bootstraps the tool from the - selected module's local configuration using temporary alternate module files, - and invokes publication with repository context, `--config`, - `--expected-module`, and semantic version. Module selection comes from the - profile; the expectation verifies table/profile agreement. The library - validates derived release identity. -4. Supply dependency preparation guidance before offline checks and illustrative - sequential core/integration publication when a sibling version must exist. - The launcher does not infer dependency order or repeat the standard suite. - -**Verification:** Run selection and launcher harnesses with local temporary -repositories and isolated dependency proxies. Cover root/nested selection, -physical-major mapping, unknown/ambiguous selection, quoted paths, and profile -agreement. Verify the selected module supplies the tool dependency and publication -receives its semantic version/profile. Shell patterns never become arbitrary -library tag templates. Update example guidance with the implemented format. - -**Completed:** Added the multi-module profiles, four-column tab-separated -mapping, shared POSIX selector, and launcher. The mapping covers root and -nested integration tags plus a physical `/v2` module layout. The launcher -copies selected module metadata outside the checkout, builds the ReleaseKit -version selected by that module, and passes the mapped profile and -`--expected-module` to publication. Guidance covers per-module dependency -preparation and sequential releases where a sibling dependency is required. -Verified selector and ambiguity behavior, unknown selections, paths with -spaces, the physical-major row, and an isolated local-proxy launcher run that -proved the selected module's tool version and publication arguments. Also -passed `sh -n`, `go test ./...`, `go run ./internal/apicheck`, and -`git diff --check`. - -## Stage 14: Bootstrap and deliver mapped module tags in Woodpecker - -**Outcome:** A maintained multi-module workflow uses the same declaration and -tagged module selection for local publication, delivery, and retries. - -**Steps:** - -1. Add a multi-module Woodpecker example under `examples/multi-module/`, with tag - filters for its root and nested selections. Keep the simpler root template. -2. Verify the literal event tag and peeled event commit, detach and check clean - source, then load the mapping/helper from that verified checkout. Select the - physical module and profile before tool bootstrap. Do not derive physical - module location merely by removing the final tag component. -3. Copy the selected module's `go.mod`/`go.sum` to temporary bootstrap metadata - outside the whole checkout; run bootstrap from that module. Build the - ReleaseKit dependency chosen there, then invoke `ci-deliver --prepared` with - repository, selected profile, expected physical module, expected commit, and - full event tag. -4. Exercise page-only and binary declarations through the same workflow. Keep - source verification, dependency preparation, and credential handling with - their established owners. A retry reads the triggering release's mapping, - profile, module files, and selected tool rather than the default branch. - -**Verification:** Workflow harnesses cover nested source-only and binary delivery, -root fallback in the separate simple template, and both physical layouts of a -major-version module. Change default-branch mapping and tool versions after a -tag and verify retry still uses its original selection. Fail inconsistent mapping -through the library's exact tag check. Isolate every synthetic dependency consumer -with test-owned `GOMODCACHE`; use local HTTP fixtures and local Git remotes. - -**Completed:** Added the multi-module Woodpecker workflow with full root and -nested tag filters, exact peeled-tag commit verification, and selection from the -verified checkout. Bootstrap uses the mapped physical module's committed Go -metadata and profile, then invokes prepared CI delivery with the expected module, -commit, and full tag. Added the binary core v2 example and documented committed -module checksums for clean binary delivery. Workflow harnesses cover nested -page-only and binary delivery, physical and virtual `/v2` module layouts, a retry -after default-branch mapping and tool changes, and an inconsistent mapping -rejected by exact event-tag validation. Tests use local Git remotes, local HTTP -delivery fixtures, a local module proxy, and test-owned `GOMODCACHE`. Verified -`go test ./...`, `go run ./internal/apicheck`, shell syntax, and `git diff --check`. - -## Stage 15: Complete consumer documentation and verify the whole cutover - -**Outcome:** The supported interface, examples, migration guidance, and behavioral -evidence describe the complete implemented feature. - -**Steps:** - -1. Update GoDoc, [CLI](../cli.md), [configuration](../config.md), - [consumer guides](../consumers/), [Gitea integration](../integrations/gitea.md), - internal owner documents, examples, and recovery guidance at their canonical - owners. Explain module selection, semantic version versus full tag, declared - versus physical module identity, note/source/license links, path bases, - boundaries, shared-file semantics, preparation, and receipt ownership. -2. Write the next release's pending notes and migration guidance. - A release version is not selected by this feature; - keep the draft under roadmap ownership until release preparation assigns its - `docs/releases/.md` destination. Include API/profile updates, the - preparation signature and tag field changes, receipt regeneration, CI mapping - and prepared mode, and root-module exclusion of nested fixture module files. - Keep immutable historical release notes intact. -3. Verify ReleaseKit's own root-module release procedure still satisfies its - adopted policy. Consumer guidance explains module-local note adaptation; - this feature does not change the source-push completion point or introduce - live-service adoption/release gates. Correct stale baseline facts in owner - documents touched by the feature, including the declared Go minimum. -4. Audit the acceptance coverage below. Add only missing representative assembled - flows or owner-level cases with a concrete remaining risk. Reuse existing - recovery, cancellation, HTTP conflict, and facade-boundary tests; avoid a - Cartesian product of every module layout, check, target, and failure. -5. Run the normal offline `go test ./...` suite and - `go run ./internal/apicheck` from the repository root. Validate affected local - documentation links/fragments and examples, and run `git diff --check`. - Record the final results and feature completion in the roadmap/plan, then - commit the completed unit. Completion is the implementation and local - evidence; tagging, deployment, live CI, and consumer rollout remain later work. - -**Verification:** Match every acceptance row to concrete test or review evidence, -record the full-suite and compiled API check results, and confirm that the -implemented examples and canonical documentation agree with the current API. - -**Completed:** Updated facade GoDoc, consumer and CLI/configuration guidance, -Gitea and internal ownership documents, recovery guidance, and maintained -examples for module selection, full tags, path bases, shared files, preparation, -and receipt ownership. Added pending next-release notes with migration guidance -and corrected the current Go minimum facts. Release preparation promoted those -notes to [the v0.4.0 release note](../releases/v0.4.0.md). -Audited acceptance coverage against -the stage-owned tests and reviewed ReleaseKit's root release procedure against -the adopted release policy; no new release gates were added. Verified -`go test ./...`, `go run ./internal/apicheck`, local links and heading fragments -in 13 changed Markdown documents, multi-module shell/config/module syntax, and -`git diff --check`. - -### Acceptance coverage audit - -| Requirement | Primary stage/evidence owner | -| --- | --- | -| One resolution per operation, committed versus working-tree declarations, major layouts, version/tag distinction | Stages 1, 2, 7; identity tests and composite coordination. | -| Root defaults, own-module declaration, no root declaration required for nested selection | Stages 1, 2, 12; resolver and representative root/nested workflows. | -| Module-local notes; equal versions at one commit; only intended tag; full-tag reuse and recovery | Stages 2, 3; candidate/publication local Git fixtures. | -| Repository-wide guards and progressive failure evidence | Stages 2, 3, 8; facade conversion and operation failure tests. | -| One selected Go suite, vet/compile/module CWD, offline environment reuse | Stage 6; validation and Go-tool tests. | -| Nested boundaries, fixtures, vendor, shared defaults/replacement/empty, committed presence, missing explicit files without checks | Stages 4, 5, 10; scope, checker, and profile round-trip tests. | -| Path deduplication, equal-blob contextual findings, cross-module lookup without expanded inputs, module-relative exclusions | Stages 4, 5; selected-view and reference tests. | -| Existing selective caches, reader cancellation and cleanup attribution | Stages 4, 5; retained regression coverage. | -| Semantic binary versions, module output paths, temporary output outside the whole repository, empty/partial builds | Stage 7; real native consumer and cross-compilation evidence. | -| New-only receipt schema and module/settings/source binding; one local delivery content pass | Stages 8, 9, 11; receipt/prebuilt/tamper fixtures. | -| Distinct hosted pages, slash tags and source links, page-only and binary delivery, unchanged partial/retry outcomes | Stage 8; HTTP fixtures and retained recovery tests. | -| Repository/profile versus module path bases; both product-command contexts; simple root configuration | Stages 10, 12; command/profile/root workflow tests. | -| Exact event checkout, prepared read-only reuse, physical-major mapping, tagged-source retries and tool selection | Stages 11–14; preparation and workflow harnesses. | -| Facade ownership, independent `buildinfo`, documentation and migration guidance, complete offline suite | Stages 2, 7, 10, 15; compiled API checks and final review. | - -No required product decisions remain open. The interface choices above provide -the starting specification; local implementation details may evolve within the -feature roadmap and repository policies. diff --git a/docs/roadmap/module-releases.md b/docs/roadmap/module-releases.md deleted file mode 100644 index d9684a4..0000000 --- a/docs/roadmap/module-releases.md +++ /dev/null @@ -1,335 +0,0 @@ -# Roadmap: release individual Go modules - -Status: implemented; post-implementation findings and corrections are recorded -in the [remediation review](remediation.md). Release version remains unselected. - -## Purpose - -Implement [ADR 0005](../adr/0005-module-release-scope.md) so a consumer can check, -publish, build, and deliver one selected Go module in a shared repository through -ReleaseKit's API and CLI. CommandKit's core and optional integrations provide the initial -consumer case. Each invocation should require only module selection, product -settings, and a semantic version, with ReleaseKit owning the common mechanics. - -This roadmap records the feature's target and resolved scope and ownership -decisions. The [implementation plan](implementation.md) records the completed -stages; [remediation](remediation.md) records review corrections. Current behavior -belongs in the [consumer guides](../consumers/), [CLI](../cli.md), -[configuration](../config.md), and facade GoDoc. - -## Historical starting baseline - -Work started from ReleaseKit v0.3.0 plus accepted ADR 0005. At that starting -point, module selection was unimplemented and the following baseline applied. - -- `ReleaseRequest` selects a repository, product, and version. `Candidate` and - `PublicationResult` expose the version without a distinct module or tag name. -- Candidate capture reads `docs/releases/.md` from the captured commit. - Local and remote uniqueness checks, tag creation, push, and reconciliation use - the version as the Git tag. -- The shared validation path runs tests, selected vet, and package compilation - from the repository directory. Optional content checks inspect the committed - repository tree, including nested-module contents. -- Profiles support shared validation and additional commands. CLI product - checks run from the repository directory with candidate/version context. -- Artifact builds and delivery also use repository/version assumptions. The - consumer Woodpecker template selects `refs/tags/v*` and bootstraps ReleaseKit - from repository-root module files. - -Candidate capture, declarative validation, exact-object publication, and outcome -reporting provided the foundation for carrying scope and identity through all -operations. - -## Targeted end state - -An invocation selects one module and one semantic version. Omitted selection -means the repository-root module. For example: - -| Selected directory | Semantic version | Complete tag | Committed release note | -| --- | --- | --- | --- | -| Root | `v0.1.0` | `v0.1.0` | `docs/releases/v0.1.0.md` | -| `integrations/ckconfig` | `v0.2.0` | `integrations/ckconfig/v0.2.0` | `integrations/ckconfig/docs/releases/v0.2.0.md` | -| `integrations/ckprompt` | `v0.1.0` | `integrations/ckprompt/v0.1.0` | `integrations/ckprompt/docs/releases/v0.1.0.md` | - -All mandatory and selected optional release checks use the selected module's -scope. Independently released nested modules are excluded from their parent's -automatic validation inputs. Shared file selections follow the -[resolved shared-file rules](#shared-file-validation-inputs). Checks may read -referenced material elsewhere in the captured repository without adding that -material's surrounding files to the input set. The checkout remains the boundary for outside-checkout link checks. - -Repository cleanliness, branch, candidate commit, remote endpoint, and publication -guards remain repository-wide. The complete selected tag governs uniqueness, -publication, and recovery. A successful source-tag push remains completion. -Consumers prepare dependencies before offline candidate validation and choose -sibling release ordering. Dependency preparation for delivery targets the -selected module through the existing preparation operation when needed. - -The feature covers individual releases. Batch publication, automatic release -selection, dependency-driven versioning, and arbitrary tag templates remain -outside this roadmap. Artifact builds, hosted delivery, and CI use the same -selected module and release identity. Delivery remains asynchronous and supports -both page-only and binary profiles. This work adds no consumer-installation, -proxy-availability, CI, or hosted-delivery publication completion gate. - -## Capability requirements - -### Module and release identity - -Repository directory, physical module directory, declared module path, semantic -version, and complete Git tag are distinct and available throughout operations -and public evidence. Shared derivation follows standard Go conventions, including -major-version layouts with and without a physical major directory. A `/v2` -module at either `integrations/ckconfig` or `integrations/ckconfig/v2` uses -`integrations/ckconfig/v2.0.0` for `v2.0.0`. Failure evidence retains resolved -identity alongside existing commit, endpoint, phase, state, and tag-object fields -as available. Facade conversions preserve underlying causes. - -### Coherent validation scope - -Tests, vet, and package compilation execute in the selected module with offline -and workspace-disabled settings. Formatting, distribution checks, file size, -and Markdown share ordered committed module and selected shared-file inputs. -Product checks receive the selected module's context. File checks retain complete -repository lookup for targeted reference reads. Existing optional check rules, -error identities, cancellation, and causes apply within that scope. - -### Notes, publication, and recovery - -Each module's committed note identifies its product and semantic version at -its module-local note path. Local and remote uniqueness, annotated tag creation, -exact-object push, and bounded reconciliation address the complete tag. -Repository-wide guards and publication outcomes remain in place. Different -modules can use equal semantic versions with distinct notes and tags. - -### Builds, receipts, and hosted delivery - -Standalone builds, candidate build checks, managed delivery builds, and prebuilt -delivery use the selected module. Module-owned execution and output paths use -that module's directory. Binaries report semantic versions; hosted pages and -source links use full tags and module-local notes. Builds and receipts carry -module and source evidence. Delivery validates that evidence and actual artifact -content before hosted requests, retaining page/asset conflicts, additive retries, -and partial outcomes. Page-only profiles require no application binary or -Go environment discovery. - -### CLI and module-selected CI - -Profiles express the API's module and shared-file selections through existing -profile lookup. Product commands receive both module and repository context. -A small shared launcher selects profiles and semantic versions. Mapped CI -selects the physical module and profile from the verified tagged checkout before -bootstrapping its selected tool. Local launchers and CI share one consumer -selection declaration. ReleaseKit verifies selection against derived identity. -Root-only consumers retain default bootstrap and profile behavior without a map. -Retries use the original tagged source's selection and tool configuration. - -### Complete adoption guidance and behavioral evidence - -Canonical API, CLI, configuration, consumer, integration, and recovery documents -and maintained examples describe the complete interface. The next release's -migration guidance covers API and profile updates, receipt regeneration, CI -selection, and root-module scope changes, including nested fixture modules. -Focused owner tests and representative assembled workflows establish the target -behavior with local repositories, HTTP fixtures, and isolated synthetic dependency -caches. The [implementation plan](implementation.md#acceptance-coverage-audit) -owns the concrete acceptance coverage and execution steps. - -## Resolved decisions - -### Resolve identity once - -Each ReleaseKit operation resolves repository directory, selected module -directory and declaration, semantic version, and complete tag once through -shared resolution logic. Pass that identity through candidate handling, -validation, callbacks, publication, builds, receipts, delivery, and evidence. -Subsystems consume the resolved module and tag. Repository-state, tagged-source, -and artifact verification continue against that identity through their existing -guards. - -### Operation prerequisites and identity - -Shared resolution supplies module and tag identity to each operation. -Candidate checking and publication retain clean source on the primary branch, -committed release notes, and their existing unused-tag checks. Delivery -retains clean tagged-source verification and supports historical releases and -detached checkouts. Ordinary builds retain their support for modified source -and operate independently of release-note and publication prerequisites. - -Composite operations pass resolved identity to their internal collaborators. -Standalone operations use the same resolver at entry, with declaration source -selected by the operation as described below. - -### Declaration source by operation - -Candidate checks, publication, and tagged delivery resolve identity from -committed module declarations. Standalone builds read the selected module's -working-tree `go.mod`, so their identity corresponds to the declaration Go -uses for compilation. This supports local development of changed module paths -and new module directories before commit. - -The operation selects the declaration source and uses shared identity derivation -logic. Composite candidate and delivery builds receive their already resolved -committed identity. Existing source-verification observations remain in place; -delivery requires a build verified against its committed tagged source. - -### One validation input set and full repository lookup - -Construct file inputs when enabled checks or explicit shared-file validation -need them. Compute module boundaries and the ordered, deduplicated input set -once using committed metadata. File checks consume that set. Keep the full -repository lookup available for targeted reads and reference resolution, with scoped reader -ownership and cancellation preserved. - -Deduplicate inputs by path. Reuse parsed results by blob identity while retaining -each source path's findings and relative destinations. This preserves the -existing selective caches and avoids retaining all inspected raw content. - -### Version and tag boundaries - -Keep semantic version and complete tag distinct in internal requests and evidence. -Version injection, artifact filenames, smoke checks, and note titles use the -semantic version. Git publication, recovery, and hosted release identity use -the complete tag. URL construction belongs to each protocol owner, which encodes -the literal tag for its route. Verify slash-containing tags in API and source -links. - -### Failure evidence - -Populate available module, version, tag, and commit evidence as resolution -progresses. Later failures retain that evidence alongside the operation's -existing phase, endpoint, tag-object, and outcome fields as available. Shared -facade conversions preserve these fields and the underlying error causes. - -### Go environment ownership - -Lazily discover effective Go settings for the selected module and reuse them -within the operation's validation and build phases when environment inputs are -unchanged. Ownership and reuse are operation-local. Dependency preparation keeps -its separate network-capable environment. Page-only delivery retains its path -without Go-tool discovery or application dependency preparation. - -### Build settings, receipts, and asset verification - -Normalize build settings once and reuse that representation for execution, -receipt binding, and comparisons. The new receipt format binds module identity -alongside existing source and artifact evidence. Loading validates structure, -identity, and file declarations. Delivery owns the content-verification pass -before hosted requests, for both API and CLI callers. - -Build-time hashing records the produced bytes; delivery-time verification -establishes that the selected files still match them. Candidate and managed -delivery output stays outside the whole repository. Ordinary output paths use -the selected module's path base. - -### CI bootstrap and checkout ownership - -For module-mapped workflows, use one small committed consumer selection -declaration shared by the launcher and CI. Bootstrap verifies the triggering -tag and commit, selects the physical module and profile, and builds the tool -from that module's configuration. ReleaseKit verifies selection against the -derived identity. - -The workflow prepares the checkout before tool bootstrap. Subsequent delivery -reuses that checkout with fresh read-only source checks. Standalone CI delivery -performs preparation when needed. Share verification behavior across these -entry paths, keeping root defaults and tagged-source selection on retries. - -### Simple single-module experience - -Ordinary root-module consumers use the new interface's defaults: omitted module -selection means the repository root, the complete tag equals the semantic -version, notes use `docs/releases/.md`, and validation and builds run -from the root module. Shared-file defaults apply with input deduplication. -Root-tag CI uses the ordinary profile and repository-root tool bootstrap. - -Routine use requires no additional configuration fields, module mapping -declarations, or recurring consumer decisions. A representative root-module -profile, launcher, and CI workflow remain equally small after migration. -Consumers supply their existing product facts through the new interface. -One-time API updates and receipt regeneration belong in the next release's -migration guidance under the clean-cutover decision below. - -### Module boundaries - -Use committed nested `go.mod` locations as module boundaries for ordinary source -directories. This follows Go's module structure and avoids a second registry of -independently versioned products. Vendored material remains part of the selected -module's file-check inputs. Nested fixture modules are excluded from automatic -parent file checks and can be exercised through the parent's tests or product -checks. Document this distinction and verify representative cases. - -A repository-level workspace file outside the selected nested module's scope -does not fail that module's workspace-file check merely because it exists. -Shared release materials and referenced destinations receive the targeted -inspection described above. - -### Shared file-validation inputs - -Provide an optional shared-file list in the public request and profile. Its -selection applies only to shared file-validation inputs. Existing validation -selections control which checks are enabled. Enabled checks retain their rules, -and Go tests, vet, and package compilation retain the selected module's scope. - -| Selection | Shared files added automatically | -| --- | --- | -| Omitted list | Repository-root `COPYRIGHT`, `LICENSE`, and `docs/oss/attribution.md`, when present. | -| Explicit list | The listed files replace the defaults. | -| Explicit empty list | No shared files. | - -In Go, a nil slice selects the defaults; a non-nil empty slice selects none. -In JSON, omission or `null` selects the defaults; `[]` selects none. Preserve -this distinction through profile mapping and facade conversions, including -slice copying and profile serialization. Resolve the defaults once. Exact field -names belong in API design. - -Paths are repository-relative literal file paths. This initial selection -supports individual files. Resolve presence and file identity from the captured -committed tree. Missing explicitly selected files produce a configuration or -validation error identifying the selected path, including when optional file -checks are disabled. Defaults are optional when absent. - -Deduplicate the combined module and shared-file inputs by committed path, so a -file already in module scope or repeated in the list is checked once. Explicit -selection may name a file in another module; include that file alone. Reference -resolution continues to inspect destinations using existing rules and leaves -those destinations outside the input set unless independently selected. - -### Relative paths and product commands - -Anchor module selection and profile lookup at the repository. Anchor -module-owned validation and build paths, including file-size exclusions, and -configured product-command execution at the selected module. Keep diagnostic -file paths repository-relative and expose both directories to product commands. -Markdown destinations remain relative to their source documents. -Normalize selections and resolve path bases at a shared boundary. Translate -file selections and exclusions to canonical repository-relative paths before -checks consume them. Use module-based filesystem paths for execution and output, -and retain repository-relative diagnostic paths through conversions. - -Root profiles use the repository-root module by default. Nested-module launchers -use the provided repository context for shared scripts. These conventions keep -per-module profiles self-contained without adding per-check path-base switches. - -### Complete operation support - -Implement module selection across checking, publication, artifact builds, -hosted delivery, and CI in this feature. The target is a coherent release API -for root and nested modules. CommandKit's current source-only use supplies an -adoption case while the feature supports the full existing release workflow. - -Feature completion includes all of these operations. Omitted module selection -uses the root module, and source publication and asynchronous delivery retain -their separate outcomes. - -### Clean API and receipt cutover - -Implement one current API and module-bound receipt format as the complete -supported interface after cutover. Consumers update their calls, profiles, and -CI declarations to that interface and regenerate prior receipts through the -updated build operation. Compatibility shims and legacy receipt readers are -outside the implementation scope. - -Migration means guidance supplied in the next release's documentation. That -guidance explains the required consumer changes and the root-module validation -scope change; implementation completion covers the new interface directly. diff --git a/docs/roadmap/remediation.md b/docs/roadmap/remediation.md deleted file mode 100644 index 33798e0..0000000 --- a/docs/roadmap/remediation.md +++ /dev/null @@ -1,587 +0,0 @@ -# Remediation: module release implementation review - -Status: complete; all fifteen findings addressed and verified. -The initial review examined `90559fe`, compared with planning baseline `dbfae9e`. -The follow-up repository audit examined `6b0b8ce`, including those corrections. - -## Scope and evidence - -The [feature roadmap](module-releases.md) and -[implementation plan](implementation.md) define the intended module-release -architecture. Most of that architecture is implemented: the two public facades, -shared module/tag derivation, scoped committed inputs with full reference lookup, -module-based Go execution, full-tag publication and hosted delivery, current-only -receipts, and tagged-source workflow selection. - -The ordinary offline `go test ./...` suite and `go run ./internal/apicheck` -passed with Go 1.26.8. The findings below also use source inspection and temporary -fixtures outside the checkout. Publication reproduction used a private local -bare repository. No ReleaseKit source or real release refs were changed. - -Each issue describes required work and verification. Preserve the selected -scope, existing error causes, publication/delivery outcomes, facade boundaries, -and clean API cutover. These corrections add no release, live-service, or human -review gates. Each completion record describes the correction and verification. - -## Issue 1: Resolve the actual Git repository root before release identity (P1) - -Status: complete. Category: architecture gap and incorrect publication. - -**Completion:** Source operations and CLI profile selection resolve the containing -Git checkout root before module selection. Regression tests verify that a child -directory cannot bypass a failing root suite or publish its tag, explicit nested -selection binds its own source and tag, aliases and independent worktrees retain -their identity, and dependency preparation works without Git. The focused public -API tests and candidate, delivery, CLI, and profile suites pass offline. - -**Evidence:** [candidate capture](../../internal/candidate/check.go) treats -`filepath.Abs(request.RepositoryDir)` as the repository root, and -[selection resolution](../../internal/releaseidentity/identity.go) uses that -directory as its base. Git committed-file paths are relative to the actual Git -root. Go commands instead execute in the supplied directory. - -A temporary repository had a failing root suite, a passing module at -`apps/widget`, and a root release note. `Check` from the actual root failed. -`Check` with `RepositoryDir` set to `apps/widget` and omitted module selection -succeeded, reporting the root module's declared path and unprefixed `v0.1.0` -tag while executing the nested suite. `Publish` with that request successfully -pushed the root tag to the private fixture remote. The declared release unit -and validated release unit therefore differ. - -**Required change:** Resolve the containing Git checkout's actual root at source -operation boundaries, then anchor repository-relative module and note paths to -that root. Carry that resolved repository identity through checks, publication, -builds, delivery, and CLI profile lookup. Normalize an input directory within the -checkout rather than introducing a blanket prohibition on such inputs. Keep -dependency preparation's own prerequisites separate; this correction should not -require a Git checkout merely to prepare a Go module's dependencies. - -**Verification:** Repeat the failing-root/passing-nested fixture through both -`Check` and `Publish`, including default CLI invocation from a nested directory. -Omitted selection must validate the actual root module and prevent publication -when that suite fails. Explicit nested selection must bind its declaration, -note, suite, and prefixed tag consistently. Retain symlinked checkout and -independent worktree behavior. - -## Issue 2: Preserve standalone Build error classification and partial evidence (P2) - -Status: complete. Category: regression and incomplete failure evidence. - -**Completion:** Standalone builds classify invalid versions before source access -and retain resolved selection and normalized build settings on identity failures. -Working-tree derivation preserves progressive identity evidence. Native CLI -validation reports invalid-version status 2 before repository access. Focused -API, native CLI, parser, identity, cancellation, and partial-artifact tests pass -offline. - -**Evidence:** [public Build](../../build.go) now calls working-tree identity -resolution before the internal builder. Invalid stable versions are returned by -`Derive` as ordinary formatted errors, bypassing the existing -`ErrInvalidVersion` identity. An API request with `bad-version` produced -`errors.Is(err, releasekit.ErrInvalidVersion) == false`; the compiled CLI exited -1 rather than its documented invalid-version status 2. - -The same entry point returns only `Version` when identity resolution fails. -Selecting an existing nested directory with an invalid `go.mod` returned empty -repository and module fields, although both directories had already been -resolved. This contradicts the roadmap's progressive failure-evidence decision -and loses supplied build facts that the previous build boundary retained. - -**Required change:** Preserve the existing invalid-version error at the build -entry boundary, including its classification before unrelated filesystem work. -Return available selection and build evidence when later declaration or identity -work fails. Share the appropriate conversion/resolution facts without resolving -the declaration again or inventing stronger source-verification guarantees. - -**Verification:** Add API and native CLI cases for invalid versions, plus a -declaration failure after successful directory selection. Assert error identity, -exit classification, and available result fields. Keep cancellation causes and -later partial-artifact behavior intact. - -## Issue 3: Use the module path base for relative prebuilt assets (P2) - -Status: complete. Category: incomplete module path adoption. - -**Completion:** Build output and CLI prebuilt assets share the selected module's -directory resolver. CLI and pending migration guidance describe the common base. -Local hosted regression tests verify root and nested relative build/delivery -pairs, absolute output, module binding, and rejection of changed artifact content -before hosted requests. Existing receipt/content checks and nested build cases -pass offline. - -**Evidence:** [CLI prebuilt delivery](../../cmd/releasekit/main.go) joins a -relative `--assets` directory to `invocation.Repository`. Builds now resolve -relative `--output` from the selected module. A nested profile's successful -`build --output dist v0.1.0` wrote -`apps/widget/dist/.releasekit-build.json`; the corresponding -`deliver --assets dist v0.1.0` attempted to open the repository-root receipt and -failed. The documented build/deliver pair therefore uses incompatible bases. - -**Required change:** Resolve relative prebuilt asset directories from the same -selected module base as build output, using shared path normalization. Preserve -absolute directories and repository-relative profile lookup. Document the base -in the CLI owner and update affected examples and migration guidance. - -**Verification:** Exercise a nested profile's relative build/output and delivery -pair using a local hosted fixture. Include the omitted root selection and an -absolute caller-owned asset directory. Verify module binding and content checks -still happen before hosted requests. - -## Issue 4: Compare receipt repository identity consistently through aliases (P2) - -Status: complete. Category: regression from mixed path normalization. - -**Completion:** Receipt source and location comparisons use filesystem directory -identity, accepting aliases of the same checkout or output directory. Regression -tests build and deliver through a checkout symlink, retry through its physical -path, and reject different repositories and modules. Receipt structure, exact -release binding, and delivery-owned content checks remain intact. Receipt and -assembled prebuilt-delivery cases pass offline. - -**Evidence:** Release identity canonicalizes repository symlinks, so generated -receipts record the physical repository directory. -[`BuildReceipt.MatchesBuild`](../../cmd/releasekit/internal/cli/receipt.go) only -applies `filepath.Abs`/`Clean` to the supplied repository. A fixture built normally -and delivered with `--repo` pointing to a symlink of that same checkout, with -an absolute asset directory, failed the preliminary repository/settings comparison. -The delivery facade's shared resolver would identify the same repository. - -**Required change:** Use consistent resolved repository identity for receipt -comparison, or leave source identity comparisons with the delivery owner that -already resolves and verifies them. Preserve structural receipt checks and exact -module/version/tag/commit binding. Avoid adding another declaration resolution -or a requirement that callers use one textual spelling of a checkout path. - -**Verification:** Build and deliver through the same symlinked checkout argument, -and through its equivalent physical path. Both must identify the same source; -a genuinely different repository or module must still fail before hosted work. - -## Issue 5: Keep Go environment reuse lazy and proportionate (P2) - -Status: complete. Category: additional validation gates and unrequested restrictions. - -**Completion:** Go discovery happens on acquisition for actual Go work. Completed -callbacks trigger no additional discovery; settings-file snapshot failures disable -reuse while preserving the Go tool's accepted configurations. Regression tests -cover check/publication completion after Go leaves PATH, subsequent builds needing -rediscovery, the final callback, unreadable GOENV snapshots, normal environment -and persistent-file changes, and cancellation. Focused public cases and complete -candidate and Go-tool suites pass offline. - -**Evidence:** [candidate coordination](../../internal/candidate/check.go) and -[publication](../../internal/publish/publish.go) eagerly call -[`Owner.Refresh`](../../internal/gotool/owner.go) after callbacks. A candidate -with successful standard validation and a successful additional callback that -left Git available but removed Go from `PATH` failed during rediscovery, although -no subsequent Go command or build was selected. `Acquire` already detects changed -inputs before actual Go work. - -The owner also requires its settings-file snapshot to be readable. With `GOENV` -set to a directory, existing `gotool.New` and the Go discovery commands succeeded, -while `NewOwner(...).Acquire` failed on the added `os.ReadFile`. Go's acceptance -of its configuration has become narrower through a cache bookkeeping step. - -**Required change:** Rediscover changed settings when a subsequent Go command -needs them. Preserve successful callback/operation completion when no more Go -work remains. Make snapshot limitations disable safe reuse or otherwise follow -the Go tool's effective behavior; they should not independently reject a -configuration that discovery accepts. Retain operation-local ownership, normal -settings-change detection, offline compilation, and separate preparation settings. - -**Verification:** Cover a completed validation operation whose callback changes -environment inputs with no later build, and one whose subsequent build actually -needs rediscovery. Compare owner discovery with the underlying Go-tool behavior -when persistent settings cannot be snapshotted. Keep existing settings-change -and cancellation tests. - -## Issue 6: Avoid requiring downloadable module paths for ordinary main modules (P2) - -Status: complete. Category: unrequested restriction. - -**Completion:** Identity derivation uses Go import-path lexical validation and -retains path-major compatibility. A valid non-domain main module now completes -candidate checking, native standalone compilation, and hosted page-only delivery -against a local fixture. Qualified and local major-version derivation, missing -and malformed declarations, and incompatible majors pass their focused offline -regression tests. - -**Evidence:** [`Derive`](../../internal/releaseidentity/identity.go) adds -`module.CheckPath`, including its requirement for a dot in the first path element. -A standard main module declared as `module example` passed `go test ./...` but -was rejected by standalone `Build` before any Go work. The -[Go module reference](https://go.dev/ref/mod#module-paths) permits main modules -that are not fetched as dependencies to use valid package paths. - -The selected requirement is stable-version and path-major tag derivation. -Deriving a root or physical-directory tag does not require the declaration to -be a downloadable network module. No user decision imposed that extra -restriction on executable applications or local builds. - -**Required change:** Validate the declaration and path-major facts needed by -identity derivation using Go's appropriate lexical rules for the supported -operations. Preserve standard major-version consistency. Remove the accidental -downloadability prerequisite rather than adding a consumer bypass setting. - -**Verification:** Exercise a valid non-domain main module through standalone -build and representative check/page delivery, alongside ordinary qualified -module paths. Continue rejecting missing/invalid declarations and incompatible -major identities for the selected release convention. - -## Issue 7: Resolve committed identity from committed material (P2) - -Status: complete. Category: declaration-source divergence and added prerequisites. - -**Completion:** Shared Git reference traversal now serves validation and committed -module identity. Committed selection follows directory and declaration links -using targeted object reads; working-tree builds retain filesystem selection. -CLI mapping and prebuilt path selection use committed directory facts. Regression -tests cover captured links, changed working declarations, cycles, checkout -boundaries, unavailable blobs, cancellation, and ordinary/prepared CI page-only -delivery from a sparse checkout without Go. The complete offline suite and -compiled public API/dependency checks pass. - -**Evidence:** - -- `FromCommittedSelection` passes raw `git show` bytes to the declaration parser. - A committed `go.mod` symlink therefore supplies its link text. In a local - fixture, Go validation and working-tree identity succeeded while committed - identity reported no valid module directive. Existing committed validation - already has reference/symlink resolution. -- `ResolveSelection` also requires the selected module directory to exist in - the worktree through `EvalSymlinks`. A clean, correctly tagged sparse checkout - retained a nested module's declaration and note in Git but omitted its physical - directory. Page-only delivery failed on `lstat` before inspecting committed - identity. Its source was present and it needed no application compilation. - -**Required change:** Separate filesystem execution selection from committed -source selection where their prerequisites differ. Resolve committed declarations -and directory/reference identity from the captured tree, retaining existing -checkout boundaries, cycle handling, missing-object errors, and cancellation. -Go execution may naturally require materialized source when it runs; page-only -metadata delivery should not gain that compilation prerequisite. Keep -working-tree builds tied to the declaration Go actually reads. - -**Verification:** Cover an in-checkout committed declaration symlink and a -page-only nested release from a clean sparse checkout with available committed -objects. Verify committed/working-tree differences deliberately and retain -reference-cycle, outside-checkout, unavailable-content, and source-tag guards. - -## Issue 8: Preserve literal shared filenames (P2) - -Status: complete. Category: unrequested path prohibition. - -**Completion:** Shared selection preserves literal backslashes in committed Git -paths. A Unix regression selects and reads such a file once despite duplicates; -traversal, absolute paths, and directories remain invalid selections. Existing -literal-metacharacter, missing/default/empty-list, scope, and lazy-input tests -pass offline. - -**Evidence:** [`normalizeSharedFile`](../../internal/validation/tree.go) rejects -every backslash. On Linux, a committed file named `docs/notice\copy.txt` is a -literal repository-relative file, but explicit selection failed as `shared-files`. -The roadmap selected literal individual paths and ordinary normalization without -globs; it did not exclude legal filename characters for committed inputs. - -**Required change:** Preserve literal committed path characters under the chosen -repository-path convention. Keep absolute/outside-repository and directory -selection checks needed for the agreed scope. Introduce neither glob expansion -nor a portability restriction on otherwise valid committed filenames. - -**Verification:** On a filesystem where backslash is a literal filename -character, select the committed file successfully. Retain traversal, missing -explicit files, literal metacharacters, deduplication, and empty/default-list -coverage. - -## Issue 9: Separate synthetic bootstrap versions from maintained examples (P2) - -Status: complete. Category: broken adoption example and incomplete cutover guidance. - -**Completion:** Maintained module skeletons no longer pin synthetic releases. -Example setup explicitly selects compatible released tooling and documents source -verification in disposable checkouts. Workflow fixtures generate their synthetic -declarations. Current-source tool registration and all three example profiles, -including native version injection, pass offline; mapped launchers/workflows and -tagged-tool retries retain isolated fixtures. Adoption and migration guidance -cover coordinated tool/workflow upgrades and historical retries. The pending -release notes record concrete example pins as normal version-selection work. - -**Evidence:** All three maintained -[multi-module declarations](../../examples/multi-module/) require ReleaseKit -`v0.2.197`. This is a synthetic test version served by -[`writeWorkflowToolProxy`](../../cmd/releasekit/multi_module_woodpecker_test.go), -whose executable forwards to the separately compiled current test binary. -A read-only query of the authoritative repository returned `v0.3.0` and no -`v0.2.197` tag. The copyable example cannot obtain its declared release tool -through ordinary module resolution. - -Published pre-feature tooling also lacks the new profile/flag interface. The -maintained workflows always pass `--prepared`, and mapped launchers additionally -pass `--expected-module`. Migration guidance does not explain that adopting the -new workflow requires a compatible tool declaration, or that an older tag's -tool declaration requires its matching historical workflow for a retry. - -**Required change:** Confine synthetic versions to test-owned module files and -proxies. Make the maintained example's setup explicitly select a ReleaseKit -version containing this feature, and update its concrete release dependency -during normal release preparation when that version is selected. Keep setup -usable for local source verification without fabricating a published release. -Document tool/workflow cutover and historical retry guidance in the pending -release notes and adoption owners. Maintain the clean API cutover; add no flag, -receipt, or source-identity compatibility shim. - -**Verification:** Tests generate their own synthetic dependency declarations -instead of relying on fake versions committed in the copyable example. Verify -the setup's selected tool accepts the actual new interface, using current source -and isolated fixtures offline. Preserve tagged-source tool-version selection and -test-owned caches. This adds no live module-service completion gate. - -## Issue 10: Remove the repeated boundary scan from file selection (P2) - -Status: complete. Category: code quality and avoidable computational cost. - -**Completion:** File selection indexes boundary directories and looks up each -entry's ancestors. Existing ordering, vendor/shared selection, full reference -lookup, and reader/cache behavior pass the complete offline validation suite. -A component benchmark retains 20,000 inputs with 0, 1,000, and 4,000 boundaries. -On this host, the 4,000-boundary case decreased from about 2.73 seconds to 38 -milliseconds per selection; the new cases ranged from 29 to 38 milliseconds. -These are illustrative measurements without timing gates or input limits. - -**Evidence:** [`selectInputEntries`](../../internal/validation/tree.go) loops -over all nested-module boundaries for every candidate entry. This costs -`O(files × boundaries)` even when the retained input set is unchanged. -Temporary committed-tree fixtures with 20,000 retained files took approximately -0.5 seconds with no boundaries, 1.0 second with 1,000 boundaries, and 2.8 seconds -with 4,000 boundaries. These timings include metadata reads and are illustrative -local measurements, not performance contracts. - -**Required change:** Use direct ancestor-boundary lookup or another straightforward -path-based selection that avoids scanning every unrelated boundary for each file. -Preserve one ordered input set, vendor handling, path deduplication, explicit -shared files, full reference lookup, and selective content-reader ownership. - -**Verification:** Retain the existing scope behavior tests and add a representative -component benchmark varying boundary count with the retained file count fixed. -Verify the algorithmic improvement without adding timing thresholds, input caps, -or new validation policies. - -## Issue 11: Reconcile documentation with implemented scope and status (P3) - -Status: complete. Category: incomplete documentation adoption and misleading contracts. - -**Completion:** Facade GoDoc and canonical API, CLI, configuration, Gitea, and -internal guidance describe selected inputs, full-tag uniqueness, module-local -notes, shared-file scope, committed references, and lazy Go reuse consistently. -The feature roadmap identifies its historical baseline and completed stages, -with this review recording the corrections. Consumer-owned license layouts and -note links are distinguished from optional validation defaults. ReleaseKit's -root release policy and procedure retain their existing requirements. Reviewed -root/nested examples, verified local links/fragments across 37 Markdown documents, -checked example JSON/shell syntax and whitespace, and passed the final complete -offline suite and compiled API/dependency checks. - -**Evidence:** - -- [Configuration](../config.md), [CLI](../cli.md), - [check guidance](../consumers/check.md), and - [publication guidance](../consumers/publish.md) still describe formatting as - including nested-module source. `Check` GoDoc similarly says local-replacement - inspection includes nested modules. Automatic input selection now excludes - independent nested modules, retaining vendor and explicitly selected files. -- Check guidance retains the old short-version wording for note location and - tag uniqueness. The new identities use physical module-local notes and full - tags, allowing equal semantic versions across modules. -- [The feature roadmap](module-releases.md) still says the feature is planned - and module selection is not implemented, while the implementation plan claims - completion. Its baseline needs to be identified as the starting baseline. -- [Gitea guidance](../integrations/gitea.md) presents root shared-license and - footer locations as an unconditional layout. Describe the default convention - and consumer-owned note links accurately; shared-file validation selection - supplies neither a license-location guarantee nor automatic footer rewriting. - -**Required change:** Refresh each affected canonical owner using the implemented -selected-input and full-tag semantics. Mark feature status accurately, including -these open remediation items, while retaining useful decision context and the -historical starting baseline. Preserve ReleaseKit's own root release policy. -Update migration/examples alongside the behavior corrections above. - -**Verification:** Review GoDoc and canonical guidance against the current code; -check root/nested examples, note and tag wording, roadmap status, local links, -fragments, and Markdown whitespace. Keep exact contract definitions at their -canonical owners. - -## Follow-up audit - -The follow-up reviewed module identity, candidate validation and publication, -builds, receipts, delivery, Go/process ownership, committed reference handling, -facade conversions, CLI/profile mapping, maintained workflows, documentation, -and the eleven previous corrections. The complete offline suite and compiled -API/dependency checks pass with Go 1.26.8. The additional findings below were -reproduced with temporary local repositories, a filtered sparse clone, a Git -transport stub, and a local HTTP server. The artifact-read evidence also used -`strace`. This audit changes the remediation document only. - -## Issue 12: Resolve module paths consistently across declaration sources (P2) - -Status: complete. Category: inconsistent release-unit selection. - -**Completion:** Filesystem selection follows symlinks before processing parent -components, matching committed traversal. Public build, candidate check, and -hosted page delivery now agree on the selected module and tag for `link/..`; -dependency preparation executes in that same module. The new regression cases -failed before the correction and pass afterward. Focused API/preparation tests -and the complete identity/Git suites pass offline, including aliases, separate -declaration sources, sparse selection, cycles, boundaries, and cancellation. - -**Evidence:** [Filesystem selection](../../internal/releaseidentity/identity.go) -cleans the joined module path before following symlinks. Committed selection -uses [component traversal](../../internal/git/path.go), following a symlink -before processing a subsequent `..`. The same selection can consequently -identify different physical modules in an unchanged, clean checkout. - -A fixture contained root and `nested` modules, a tracked directory -`nested/deep`, and `link -> nested/deep`. With `ModuleDir: "link/.."` and -`Version: "v0.1.0"`, public `Build` succeeded with the root module and tag -`v0.1.0`; public `Check` succeeded with the nested module and tag -`nested/v0.1.0`. Working-tree and committed declaration readers independently -confirmed the difference. Dependency preparation uses the filesystem selector, -while candidate and delivery operations use committed selection. - -**Required change:** Give filesystem and committed selection the same component -and symlink semantics for identical paths in an unchanged checkout. Preserve -the agreed declaration source for each operation, support for working-tree -changes and committed sparse selection, checkout boundaries, and progressive -identity evidence. Module paths containing `..` need consistent resolution; -this correction does not require prohibiting those paths. - -**Verification:** Exercise a tracked directory symlink followed by `..` through -standalone build, candidate check, dependency preparation, and representative -delivery. An unchanged checkout must identify the same physical module and tag -across operations. Retain deliberate committed/working-tree declaration -differences, ordinary aliases, cycles, and outside-checkout failures. - -## Issue 13: Reuse local asset verification through the complete delivery path (P2) - -Status: complete. Category: incomplete verification ownership and redundant I/O. - -**Completion:** Assembled delivery reuses its preflight verification through the -internal upload path; standalone internal uploads retain local verification. -A Linux filesystem-event regression observes one verification read and one -upload read across public delivery and validates uploaded contents. It failed -with three reads before the correction. Delivery/Gitea suites pass offline, -including tampering, caller ownership, matching attachments, and partial retries. -The complete-delivery benchmark now supplies current module identity. Its 32 MiB -fresh-upload case measured about 352 ms before and 254 ms afterward on this host; -these illustrative measurements introduce no timing gate. - -**Evidence:** [Delivery](../../internal/delivery/delivery.go) calls -`VerifyLocalAssets` before hosted requests. After release and attachment -inspection, [UploadMissing](../../internal/gitea/upload.go) calls -`verifyLocalAsset` again for every missing attachment. Both calls stream and -hash each local binary. The upload then reads it a third time to send its bytes. -Stages 8 and 9 of the [implementation plan](implementation.md) select one -delivery-owned content-verification pass. - -A public prebuilt-delivery fixture completed against a local HTTP server with -one missing binary and its manifest. A system-call trace recorded three complete -reads of the binary: the delivery preflight, the uploader's repeated verification, -and the multipart upload. Receipt loading is already free of artifact hashing; -the remaining duplicate sits across the delivery/Gitea boundary. The current -asset-preflight benchmark ends before that second verification. - -**Required change:** Reuse the completed local verification in the assembled -delivery path so each binary receives one delivery-time digest-and-size pass -before hosted requests, followed by its necessary upload stream. Preserve -validation for independently used internal client operations, build-time -hashing, deterministic manifests, actual remote-content comparison, additive -retry behavior, caller-owned files, and existing failure outcomes. - -**Verification:** Observe file reads across a complete public binary delivery -with missing attachments, covering the uploader as well as preflight. Establish -one verification read plus the upload read. Keep tampered/missing-file rejection -before hosted requests and matching-asset/partial-retry cases. Measure the whole -local path without timing thresholds or additional source guarantees. - -## Issue 14: Keep committed release-note inspection within the local object boundary (P2) - -Status: complete. Category: incomplete earlier offline-inspection correction. - -**Completion:** Committed-file reads now use the shared local-only Git object -runner. Filtered-clone regressions cover direct reads plus public check and -delivery with an unavailable note, preserving the note path, Git cause, and -captured identity while making no hosted request, transport attempt, or object -database change. Both regressions exposed transport before the correction. -The Git/candidate suites and focused source, page-delivery, and explicit tagged -checkout preparation cases pass offline; ordinary note bytes and cancellation -handling retain their existing command boundary. - -**Evidence:** [ReadCommitFile](../../internal/git/source.go), used by candidate -capture and delivery for release notes, executes `git show` through the ordinary -Git runner. Its child does not receive the lazy-fetch and transport controls -used by `ReadBlob`, committed-path lookup, tree inspection, and the batch reader. -An unavailable note in a partial clone can therefore initiate remote transport -during source inspection. The earlier correction in `0205001` and its partial -clone tests cover the other object readers, leaving this entry point uncovered. - -A clean filtered sparse clone had its root declaration and Go source locally -available, with the committed note omitted and its blob unavailable locally. -Public `Check` resolved the root identity, then invoked a fixture SSH transport -while reading `docs/releases/v0.1.0.md`. The stub recorded the attempt and exited; -the resulting error reported failure to fetch the note from the promisor remote. -The fixture contacted no external service. - -**Required change:** Read committed note bytes through the same local-only object -boundary as the other source-inspection readers. Return an inspection error -when required objects are unavailable locally, preserving path context, -cancellation, underlying Git causes, and exact note bytes. Explicit checkout -and dependency preparation retain their network-capable responsibilities. - -**Verification:** Cover direct committed-file reading and representative -candidate/delivery note inspection in filtered clones with unavailable note -objects. A controlled transport stub must remain unused, and inspection must -leave the object database unchanged. Existing ordinary note reads and explicit -network-capable preparation must continue to work. - -## Issue 15: Limit blob availability requirements to selected validation inputs (P2) - -Status: complete. Category: module-scope leakage through eager metadata enrichment. - -**Completion:** Tree enumeration now acquires path/type/mode/object metadata -independently of blobs. The size check requests sizes only for selected, -non-excluded blobs; other checks read contents and references when needed. -Filtered sparse-clone regressions cover formatting, sizes, workspace metadata, -explicit shared selection, exclusions, required shared contents, and required -Markdown references. They failed before the correction and now preserve each -check's scope and error identity without transport or object-database changes. -Existing size, symlink, gitlink, vendor, boundary, reader/cache, and cancellation -tests pass. The complete offline suite, compiled API/dependency check, -documentation links, and whitespace checks pass for all four follow-up fixes. - -**Evidence:** [ReadCandidateTreeForScope](../../internal/validation/tree.go) -calls [ReadTree](../../internal/git/source.go) before constructing module and -shared-file inputs. `ReadTree` asks `populateBlobSizes` for every repository blob -and fails on any unavailable object. Excluded modules and unreferenced files -therefore become availability prerequisites for a selected module's file checks, -even when the selected check needs no blob sizes. - -In a clean filtered sparse clone, the root module's source, declaration, and -note were available; independently scoped `nested` module blobs were omitted. -Public root `Check` succeeded with ordinary validation. Enabling `GoFormat` -with an explicit empty shared-file list made the same check fail during size -enumeration on the unavailable blob for `nested/deep/placeholder`. That file -belongs to the excluded nested module and is neither a formatting input nor a -referenced destination. - -**Required change:** Separate full repository path/type/object metadata from -blob enrichment. Construct the agreed input set before acquiring required blob -sizes or contents, and inspect referenced destinations when a check actually -needs them. Keep full lookup available without requiring every unrelated blob -locally. Preserve selected-input ordering, boundaries, vendor/shared selection, -size semantics, local-only reads, cancellation, and reader ownership. - -**Verification:** Use a filtered sparse fixture with a complete selected module -and unavailable blobs in an excluded sibling or nested module. Representative -formatting, file-size, and explicit shared-file validation must work when their -required inputs are available. A selected missing blob or required referenced -destination must still produce the appropriate inspection error. Verify that -excluded unreferenced blobs cause neither content reads nor transport. diff --git a/examples/multi-module/README.md b/examples/multi-module/README.md index f298ec6..8b8ae86 100644 --- a/examples/multi-module/README.md +++ b/examples/multi-module/README.md @@ -27,10 +27,10 @@ done ``` Review and commit the generated tool, dependency, and checksum declarations. -Release preparation records the chosen compatible version in these maintained -module files. The feature roadmap leaves that release version to release -preparation. The [adoption guide](../../docs/consumers/adoption.md) owns tool -registration and coordinated tool/workflow upgrades. +The [adoption guide](../../docs/consumers/adoption.md) owns tool registration and +coordinated tool/workflow upgrades. The +[v0.4.0 release note](../../docs/releases/v0.4.0.md) describes module-release +support and migration from earlier versions. ## Module mapping and publication