diff --git a/docs/roadmap/audit.md b/docs/roadmap/audit.md index f1b6028..37001c6 100644 --- a/docs/roadmap/audit.md +++ b/docs/roadmap/audit.md @@ -1,43 +1,41 @@ # ReleaseKit pre-release audit Date: 2026-10-06. Reviewed source: `536a57916f6565ae8194c4563577dfcebd6cfb69`. -Status: findings and recommendations; no design changes adopted by this document. +Status: review findings and proposed changes, revised for the clarified product goals. Audience: maintainers deciding the shared release standard before `v0.1.0`. ## Assessment -ReleaseKit is a sound foundation for the intended standard, but I recommend -resolving two reproduced correctness defects and one demonstrated build-standard -gap before tagging it. Its publication -and delivery separation, narrow public facades, standard artifact naming, -version injection, and content-aware delivery retries are worth retaining. -The implementation covers most of the mechanics in the -[product roadmap](releasekit.md). It does not yet demonstrate both -[architectural success criteria](../policy/architecture.md#success-criteria): -substantial removal of consumer infrastructure and adoption of one coherent -standard. Those require representative adoption evidence. +ReleaseKit's practical goals are to minimize application-owned release code, +duplication across the suite, and the time developers spend on release processes. +Shared conventions serve these goals by giving routine decisions one owner. +Applications supply product facts and product-specific checks; ReleaseKit owns +the procedure, sensible defaults, and recovery guidance. -The main architectural choices have concrete benefits: annotated tags preserve -the checked-in note and provide an exact object for recovery; requiring the -candidate on authoritative `main` keeps branch publication out of the release -transaction; and separate delivery prevents a hosting outage from redefining -source-release success. None needs replacement to achieve the stated goals. -Selected build targets and product-specific checks are appropriate variation; -independent implementations of the publication transaction are not. +The core direction is sound. Retain the publication/delivery separation, narrow +public facades, standard artifact naming, version injection, and content-aware +retries. Fix the reproduced validation and recovery defects in F1–F2 before +`v0.1.0`. Treat F3 as a focused improvement to internal build defaults. -The larger design opportunity is to make ReleaseKit own more of the ordinary -path: a standard validation baseline, a declared build environment, and shared -delivery orchestration usable equally through Go and the CLI. Today, consumers -can still supply an entire replacement validation process, repeat CI setup, and -assemble binary delivery themselves when using the Go API. These are supported -choices, not violations of the present contracts, but they weaken the stated -objective of minimizing variation. +Build-environment reproducibility, hardware-specific configurability, and +extensive build inspection are outside the product's optimization goals. Use the +available compatible Go toolchain and shared baseline settings. Evaluate new +configuration and deployment machinery by the application code and developer +work they save. Different toolchains may produce different bytes; existing +published content remains protected by digest comparison. -Compatibility with existing consumer scripts is not a reason to preserve these -choices. The recommendations below favor a coherent long-term standard, while -retaining product identity, target selection, compatibility decisions, and -product-specific behavioral checks with the consumer. They do not propose -mandatory new lint, race, signing, live-service, or approval gates. +The implementation covers most mechanics in the [product roadmap](releasekit.md). +Representative adoption should demonstrate the +[architectural success criteria](../policy/architecture.md#success-criteria) +through deleted release code, fewer duplicated checks, and fewer routine decisions. +F4–F6 identify opportunities to centralize validation, delivery, and CI setup. + +The existing source transaction supports these goals. Annotated tags preserve +the checked-in note and provide an exact object for recovery. Requiring the +candidate on authoritative `main` keeps branch publication in preparation. +Separate delivery lets source publication finish independently of hosting. +Consumer migrations should adopt this common process and retain product identity, +target selection, compatibility decisions, and product-specific checks. ## Scope and evidence @@ -45,13 +43,13 @@ Reviewed the development guide; agent, architecture, testing, documentation, and release policies; facade ADR; roadmap; public declarations; CLI/configuration and consumer guides; publication, build, delivery, Git and Gitea implementations; and their relevant tests and workflow examples. The -[release policy](../policy/release.md) governs ReleaseKit's own releases; its -requirements are not automatically imposed on every consumer API operation. +[release policy](../policy/release.md) governs ReleaseKit's own releases. +The facade and integration contracts define consumer behavior. Also inspected the release scripts, module declarations, and available delivery -YAML in the six sibling projects named by the roadmap. This was a read-only -sample of adoption needs, not an audit or migration of those repositories. -Their existing extra checks are evidence to evaluate, not requirements to copy. +YAML in the six sibling projects named by the roadmap. This read-only sample +informed the assessment of adoption needs. +Existing extra checks should be retained according to their product-specific value. For example, PromptKit has product-specific executable examples, whereas Narratio currently requires Go 1.26 and several peers require Go 1.25.5. @@ -61,14 +59,13 @@ Validation on Linux/amd64 with Go 1.26.8: passed on the reviewed checkout. - `go run ./internal/apicheck` passed. - Isolated probes against an archive of the reviewed commit reproduced F1–F3 - below. They used temporary consumer repositories and local bare Git remotes; - no production refs, credentials, or hosted content were used. + below. They used temporary consumer repositories and local bare Git remotes. -The probes were investigative tests in a disposable checkout, not additions to -the default suite. Their setup and outcomes are recorded with each finding so -regressions can be written against the intended fixes. No live Gitea or -Woodpecker deployment, published-module installation, or minimum-Go-1.25 run was -performed. The test pass therefore does not establish those properties. +The investigative probes ran in a disposable checkout. Their setup and outcomes +are recorded with each finding for future regressions. Validation covered local +fixtures on Go 1.26.8. Live Gitea/Woodpecker integration, published-module +installation, and minimum-Go-1.25 compatibility remain unverified. These results +belong to the original source review; this revision updates its recommendations. ## Goal coverage @@ -77,10 +74,10 @@ performed. The test pass therefore does not establish those properties. | One standard source-publication transaction | Substantially implemented in [Publish](../../internal/publish/publish.go): captured candidate, authoritative `main`, annotated tag, exact object/ref push, and bounded recovery. F2 is a correctness exception. | | One validation of the intended candidate | Callback/default validation plus mutable-state rechecks are implemented in [candidate](../../internal/candidate/check.go). F1 can silently narrow the default suite; F4 concerns the selected customization model. | | Consumer-selected binaries or source-only releases | [Build](../../internal/build/build.go) supports target pairs and empty sets. Source-only delivery creates no binary manifest. This is the right distinction. | -| Shared runtime version, build flags, naming, and smoke check | Implemented through [buildinfo](../../buildinfo/version.go), the builder, and external consumer build tests. F3 leaves important build inputs ambient. | +| Shared runtime version, build flags, naming, and smoke check | Implemented through [buildinfo](../../buildinfo/version.go), the builder, and external consumer build tests. F3 identifies an opportunity for predictable internal defaults. | | Immutable hosted contents and recoverable partial delivery | [Delivery](../../internal/delivery/delivery.go) and [Gitea](../../internal/gitea/) compare notes and asset bytes, reject conflicts, and add missing assets. F7 identifies an outcome-reporting inconsistency. | | Public contract ownership and small runtime dependency graph | Root and runtime facades follow [ADR 0001](../adr/0001-public-facade.md); compiled boundary checks pass. Keep these boundaries. | -| Thin application integration and less repeated infrastructure | Plausible but not demonstrated by consumer adoption. F5–F6 identify remaining orchestration and setup duplication. | +| Thin application integration and less repeated infrastructure | Representative consumer adoption remains to be evaluated. F5–F6 identify remaining orchestration and setup duplication. | | Ready deployment path | Prepared templates and local fixtures exist. Immutable deployment pins, credentials, activated workflows, and live verification remain explicitly open in the roadmap. | ## Findings @@ -104,27 +101,26 @@ The [Go command documentation](https://pkg.go.dev/cmd/go#hdr-Environment_variabl confirms that `GOFLAGS` supplies defaults to commands that recognize its flags. **Consequence.** A normal developer setting used for focused testing can cause a -release to pass without the complete default suite. The caller need not edit -source or intentionally bypass validation. +release to pass after skipping the default suite. The reproduction uses an +unchanged committed candidate and an ordinary shell setting. **Recommendation.** Make the standard validation command own its effective Go flags and host target, including values supplied through Go's persistent configuration. Preserve caches and legitimate dependency preparation settings. -Use one internal Go-environment policy shared with the builder where appropriate; -do not give validation the builder's `CGO_ENABLED=0` blindly. A standard native -test run and a static release build have different needs. Apply the same baseline -to ReleaseKit's own profile. Retain a regression that proves a failing test -cannot disappear under an ambient filter. F4 and Open Question 1 address how +Share internal Go-environment handling where the semantics match. Preserve +the settings appropriate to native tests and static release builds separately. +Apply the same baseline to ReleaseKit's own profile. Retain a regression showing +that a failing test remains effective under an ambient filter. F4 and Open Question 1 address how intentional product-specific checks should compose with this baseline. ### F2 — High: automatic push recovery can query a different endpoint and report false absence **Evidence.** [reconcilePush](../../internal/publish/publish.go) calls `Endpoint.QueryTag` using the captured URL and command-scoped remote. -[QueryTag](../../internal/git/tag.go) does not call -`verifyScopedURLs`, although [Resolve/Recheck](../../internal/git/remote.go) -use that verification before publication. Git still applies current URL rewrite -configuration to the captured literal URL. The manual recovery instructions in +[QueryTag](../../internal/git/tag.go) runs the query directly. +[Resolve/Recheck](../../internal/git/remote.go) call `verifyScopedURLs` before +publication. Git still applies current URL rewrite configuration to the captured +literal URL. The manual recovery instructions in [the runbook](../release.md#resolve-failures) already require a URL-equality check. The automatic path lacks the equivalent check. @@ -137,25 +133,21 @@ shows the exact tag object returned in `PublicationResult` is present. **Consequence.** The result gives incorrect recovery advice after an ambiguous push. It converts a query to the wrong endpoint into proof that the intended -endpoint lacks the published tag. This contradicts an existing recovery -contract; it is not a request for broader filesystem or transport hardening. +endpoint lacks the published tag. This contradicts the existing recovery +contract for the authoritative endpoint. **Recommendation.** Within the existing bounded recovery context, verify that the captured endpoint still resolves to itself before the one authoritative tag query. If verification fails, preserve the push error and local tag and return -`unknown`. Do not resolve the remote name anew and substitute its current -endpoint. Cover both the successful-publication/false-absence reproduction and -an ordinary unchanged-endpoint recovery. No extra read-back gate is needed after -a successful push. +`unknown`. Keep recovery bound to the captured endpoint. Cover the +successful-publication/false-absence reproduction and ordinary recovery against +an unchanged endpoint. Preserve successful push as the completion point. -### F3 — High for binary adoption: target identity omits effective build inputs +### F3 — Internal improvement: ambient CPU settings change binary compatibility **Evidence.** `goEnvironment` in [internal/build/build.go](../../internal/build/build.go) -standardizes several Go settings but inherits architecture feature variables, -`GOEXPERIMENT`, and the persistent Go environment file. Build identity records -GOOS/GOARCH and compiler text, but not those effective inputs. The -[receipt](../../cmd/releasekit/internal/cli/receipt.go) and public `BuildResult` -cannot distinguish their effects. +standardizes several Go settings and inherits architecture feature variables, +`GOEXPERIMENT`, and the persistent Go environment file. **Reproduction.** Build the same committed consumer and `v1.2.3` for `linux/amd64` twice, once with `GOAMD64=v1` and once with `GOAMD64=v2`. @@ -165,23 +157,20 @@ records the respective feature levels. Go documents these as different target microarchitecture requirements in its [environment reference](https://pkg.go.dev/cmd/go#hdr-Environment_variables). -**Consequence.** Identical declared targets can require different CPUs and yield -conflicting bytes during delivery retries. Existing content comparison correctly -refuses replacement, but cannot make an undeclared build environment repeatable. -A clean Git checkout does not resolve this; `SourceVerified` correctly makes no -attestation claim. This is a gap in the desired shared build standard, rather -than a violation of a documented promise of fixed CPU baselines or reproducible -bytes. The missing selection should be made deliberately before binary adoption. +**Consequence.** A developer's ambient CPU setting can narrow a binary's hardware +compatibility. Different build inputs can also produce a digest conflict during +a delivery retry. Existing digest comparison correctly preserves published bytes. +This finding supports predictable defaults; its earlier high-priority assessment +placed too much weight on build-environment standardization. -**Recommendation.** Select documented baseline architecture features for the -supported targets and control the relevant environment and Go configuration -file. Choose the release toolchain explicitly and preserve that selection with -the tagged declaration or immutable delivery environment. If custom feature -levels are supported, declare them and include them in artifact/build identity. -Do not silently derive them from a developer shell. Reuse the selected inputs -for candidate builds and tagged delivery. See Open Question 2 for the tradeoff -between a fixed baseline and richer declared variants. This recommendation does -not promise universally reproducible or hermetic builds. +**Recommendation.** Use ordinary baseline CPU settings and shared build flags +internally, with the available compatible Go toolchain. Control incidental +settings that affect expected compatibility or validation. Keep the application +profile focused on its package, binary name, and targets. Exact toolchain +pinning and detailed build metadata remain optional operational choices. +When a retry requires the original bytes, preserve and reuse those artifacts. +Open Question 2 compares local toolchain use with a centrally maintained build +environment for consumers that benefit from shared setup. ### F4 — Design priority: adding a custom check replaces the entire standard suite @@ -193,43 +182,41 @@ replacement `Validate` callback. **Consequence.** Adding one product-specific example check requires the consumer to remember and reproduce the standard test command, environment, and ordering. -The profile becomes a small alternative release program. This relocates shared -policy instead of fully centralizing it. Conversely, simply adding mandatory -default tests to the current behavior would run them twice for existing check -scripts that already run the suite. +The profile becomes a small release program that repeats shared policy. Migrating +to built-in tests requires removing their invocation from existing custom scripts +to preserve one suite run. -**Recommendation.** Before first adoption, select a baseline-plus-additional-checks -model, with a narrow explicit way to express a justified alternative test -invocation when necessary. Migrate redundant suite invocations out of consumer -scripts. Keep only checks for actual product behavior, such as PromptKit's -examples. Do not preserve every consumer's race/vet/build loop merely to avoid -breaking their old workflow. This is a proposed contract change, not a bug fix; -Open Question 1 records a viable replacement-callback alternative. +**Recommendation.** Run the shared offline suite once, followed by optional +product-specific checks. Move redundant suite invocations out of consumer scripts. +Retain checks for actual product behavior, such as PromptKit's examples. Add +alternative test-invocation settings when a concrete consumer requirement +justifies them. This proposal changes the current customization contract; Open +Question 1 records the replacement-callback alternative. ### F5 — Design priority: the CLI owns reusable tagged-build delivery orchestration **Evidence.** [runDelivery](../../cmd/releasekit/main.go) chooses a temporary output directory, invokes the public builder, converts receipts, and then calls `Deliver`. The [public delivery request](../../delivery.go) accepts an already -produced `BuildResult`, not a build declaration. A Go consumer wanting the normal -build-and-deliver operation must reproduce orchestration that CLI consumers get -for free. The default CLI path also builds and runs the native smoke executable +produced `BuildResult`. A Go consumer wanting the normal build-and-deliver +operation must reproduce orchestration already implemented by the CLI. The +default CLI path also builds and runs the native smoke executable before `Deliver` verifies that HEAD matches the selected local tag. **Consequence.** Temporary storage, build sequencing, tagged-source preflight, and cleanup have more than one potential owner. An invalid tagged checkout can -consume a complete cross-build before it is rejected. The CLI does use supported -facades, but owns more domain coordination than the architecture's parsing, -presentation, and exit-status responsibility suggests. +consume a complete cross-build before it is rejected. The CLI owns domain coordination +alongside its parsing, presentation, and exit-status responsibilities. **Recommendation.** Put the ordinary verify-tagged-source, build-selected-targets, and deliver sequence behind the orchestration facade. Verify the local tagged source before expensive compilation, then retain the necessary checks before remote effects. Let the CLI adapt JSON, credentials, and output to that operation. Use the same build declaration for candidate validation and delivery. Decide -whether caller-provided builds remain an advanced supported mode, as discussed -in Open Question 3. Keep the private receipt as local coordination data if that -mode remains; do not promote it into a provenance or portable-attestation format. +whether a concrete consumer needs caller-provided builds, as discussed in +Open Question 3. Keep separate building useful for local development. The ordinary +consumer workflow should complete delivery in one invocation; advanced artifact +handoffs can use private coordination data when needed. ### F6 — Adoption priority: shared deployment still depends on copied mechanics @@ -241,31 +228,27 @@ the CLI already supports combined delivery. ReleaseKit's [own workflow](../../examples/woodpecker/releasekit-source-delivery.yml) has a separate first-release bootstrap. Consumer pins remain placeholders as documented. -**Consequence.** Core library duplication is reduced, but routine CI mechanics -still become consumer-owned copies that can drift. A chosen ReleaseKit version -and Go toolchain also need a clear installation/update convention for both local -publication and CI delivery. Merely requiring every application to invent a -wrapper would leave part of the roadmap's original problem unsolved. +**Consequence.** Copied CI mechanics require maintenance in each consumer and +can drift. A shared installation and update convention would simplify local +publication and CI delivery. -**Recommendation.** Provide a maintained, versioned integration entry point and -one default delivery sequence for both source-only and binary profiles. Keep -product declarations, immutable tool/toolchain pins, and secret references in -consumer configuration. Keep network-enabled dependency preparation separate -from offline validation/builds. Splitting build and delivery is justified when -it establishes an actual credential or artifact handoff boundary, not simply -because both commands exist. See Open Question 4 for packaging alternatives. -ReleaseKit's bootstrap can remain special until the first version is available. +**Recommendation.** Provide one maintained integration entry point and one +default delivery sequence for source-only and binary profiles. Consumers select +the ReleaseKit version, supply product settings, and provision credentials. +Centralize installation and update instructions. Choose source installation or a +maintained image according to the setup and maintenance effort each saves. +Keep dependency preparation separate from offline validation/builds. A split +build/delivery flow remains useful for an actual credential boundary or artifact +handoff. See Open Question 4 for packaging alternatives. -The current workflow tests are useful but narrower than their names may imply. `TestWoodpeckerDeliveryCommandSequences` in [the CLI workflow tests](../../cmd/releasekit/woodpecker_test.go) executes equivalent commands; [the ReleaseKit workflow test](../../cmd/releasekit/releasekit_delivery_workflow_test.go) -similarly reconstructs the sequence. They do not execute the maintained YAML -through Woodpecker or exercise the pinned installation step. A YAML drift can -therefore leave those tests green. Validate the actual selected integration at -adoption, and keep a small check tied to the maintained artifact. This is -integration-development evidence, not a new per-release live-service gate. +similarly reconstructs the sequence. Execution of the maintained YAML and +installation step remains unverified. A YAML drift can leave these tests green. +Validate the selected integration during adoption and keep a small check tied to +the maintained artifact. Use that evidence to maintain the shared integration. ### F7 — Medium: delivery asset classifications overlap inconsistently @@ -278,19 +261,18 @@ can also remain pending. The existing [upload_test.go](../../internal/gitea/upload_test.go) explicitly expects the same asset in both pending and uncertain collections. -**Consequence.** Public consumers cannot treat the collections as consistent -categories. The CLI can present one file as both pending and uncertain, while a +**Consequence.** Overlapping categories require special handling by consumers. +The CLI can present one file as both pending and uncertain, while a slightly different failure reports it only as uncertain. The overall unknown -state is conservative, so this is not a false-success defect, but it makes -recovery reporting and automation less clear. +state remains conservative. Consistent categories would simplify recovery +reporting and automation. **Recommendation.** Prefer mutually exclusive current-outcome categories: confirmed matching, uploaded, known pending, conflicting, and uncertain. Move an asset out of pending when its outcome becomes uncertain or conflicting, and clarify the facade GoDoc. Alternatively, explicitly define pending as a superset of all unfinished assets and implement that rule consistently; see Open -Question 5. Update the behavioral tests to protect the selected meaning instead -of preserving inconsistent branch bookkeeping. +Question 5. Update behavioral tests to protect the selected meaning. ### F8 — Maintainability: artifact rules have several implementation owners @@ -310,137 +292,114 @@ why divergent Go-environment ownership matters beyond cosmetic duplication. **Recommendation.** Give internal build/artifact rules one owner and reuse them from receipt and delivery adapters. Share Go invocation/environment construction -where the semantics actually match. Keep explicit facade conversions required -by the ADR; replacing them with public aliases would trade a little duplication -for a larger compatibility burden. Do not introduce a generic workflow engine, -plugin registry, or public Git/Gitea implementation packages to solve these -localized problems. +where the semantics match. Keep the explicit facade conversions required +by the ADR. Focus refactoring on the small internal helpers that own these rules. ## Recommended standard and release sequencing Retain the existing source transaction: committed stable-version note, clean `main`, candidate already on authoritative `main`, one validation, selected-target -build verification, exact annotated-tag publication, and bounded ambiguity -recovery. Source publication finishes independently of hosted delivery. Keep -additive, content-checked delivery and lightweight runtime version access. +build verification, exact annotated-tag publication, and bounded recovery. +Source publication finishes independently of hosted delivery. Keep additive, +content-checked delivery and lightweight runtime version access. -Strengthen that standard around a small committed declaration: product identity, -selected binary targets, explicit toolchain/build choices, delivery destination, -and product-specific checks added to the shared validation baseline. The ordinary -consumer integration should be a pinned tool invocation plus that declaration -and secret provisioning. Authoring compatibility notes and choosing the version -remain product decisions; ReleaseKit need not guess them from commit messages. +Make ordinary integration a versioned tool invocation plus a small product +profile and credential provisioning. The profile supplies product identity, +selected binaries and targets, delivery destination, and product-specific checks. +ReleaseKit owns the standard suite, routine build settings, delivery sequence, +and recovery reporting. Product developers choose versions and write +compatibility notes. Evaluate each proposed setting by the work it saves them. Recommended order: -1. Fix F1–F3 and retain focused behavioral regressions. F1–F2 affect the first - source release itself; F3 should be resolved before advertising standard - binary adoption. -2. Decide Open Questions 1–3 and 5 before settling the first public API and - configuration contracts. Implement the selected changes, including F7, with - their canonical GoDoc/configuration/consumer documentation. Consolidate F8 - while touching those owners. -3. Prove one representative source-only integration with an extra product check - and one binary integration using the selected common workflow. Identify the - actual scripts and duplicated tests removable from each. Temporary local - adoption trials can precede a published module; do not make sibling checkouts - dependencies of ReleaseKit's normal build or default suite. -4. Select the packaging direction in Open Question 4, prepare immutable pins and - credentials, and test the actual workflow/service integration separately. - First-source-release bootstrap is legitimate; live artifact availability - still does not become a source-publication completion gate. -5. Prepare the `v0.1.0` note and follow the existing maintainer procedure once the - selected pre-release work is complete. This audit does not tag or publish. +1. Fix F1–F2 and retain focused behavioral regressions before tagging `v0.1.0`. +2. Settle the validation and delivery API choices in Open Questions 1 and 3. + Adopt clear result categories under Question 5. Implement the selected + changes with their canonical documentation and consolidate F8 in those owners. +3. Address F3 through internal compatibility defaults, using Open Question 2 to + keep build configuration proportionate to actual consumer needs. +4. Exercise one source-only consumer with an extra product check and one binary + consumer through the common integration. Measure removed scripts, duplicated + tests, setup steps, and recurring release decisions. Keep ReleaseKit's default + suite independent of sibling checkouts. +5. Choose the simplest shared installation and update path under Open Question 4. + Verify the maintained integration during deployment preparation. Follow the + existing maintainer procedure for the release note and source publication; + report hosted delivery separately. -Not every possible release feature belongs in this first version. There is no -review evidence requiring a general multi-module release engine, prerelease -channels, multi-program bundles, arbitrary packaging hooks, mandatory signatures, -or stronger source attestations. Add such capabilities for an adopted need, -without weakening the ordinary shared path to accommodate hypothetical cases. +Feature expansion should follow demonstrated consumer needs and measurable +reductions in application maintenance or developer effort. ## Open Questions ### 1. Should product checks supplement or replace standard validation? -**Recommended:** Run the shared offline suite once, followed by declared -product-specific checks. Where a product truly needs a different invocation of -that same suite, expose a narrow explicit selection with documented semantics, -not an unrestricted implicit replacement. This centralizes the shared obligation -while allowing meaningful product checks and avoiding duplicate tests. Remove -old suite invocations when migrating custom scripts. +**Recommended:** Run the shared offline Go suite once, followed by optional +product-specific checks. ReleaseKit owns the command and its routine environment +settings. Migrate repeated suite invocations out of application scripts. Add +alternative invocation settings when an actual consumer requirement establishes +their value. This gives developers one ordinary validation path to understand. -**Viable alternative:** Keep the current replacement callback/command list and -make each product own one complete validation command. This is idiomatic for a -small Go orchestration library and accommodates unusual test layouts without an -expanding configuration schema. It is optimal if validation is intentionally a -consumer boundary; it is less aligned with the user's goal of maximal shared -standardization. Adoption guidance and tests would need to establish the common -baseline rather than assuming the library enforces it. +**Viable alternative:** Keep a replacement callback or complete validation +command for products with unusual test layouts. This is a simple composition +boundary and can accommodate existing product test infrastructure. It assigns +more release responsibility to the application, so its value depends on the +specific consumer need. -### 2. How much of the build environment belongs in release identity? +### 2. How should ReleaseKit choose build settings? -**Recommended:** Standard baseline feature levels and flags, plus an explicitly -selected toolchain preserved with the release inputs or an immutable build-image -pin. Control ambient feature/experiment settings and persistent Go configuration. -Keep cache locations and dependency access during preparation operational. -Different products can select toolchains meeting their modules' requirements; -standardization is the selection mechanism, not forcing every product onto an -inadequate Go version. This minimizes accidental variants and makes retries -explainable without claiming hermeticity. +**Recommended:** Use the available compatible Go toolchain, ordinary baseline CPU +settings, and shared build flags. Handle incidental environment settings internally +so developers can rely on the selected target's expected compatibility. Keep +application configuration small. Toolchain-dependent byte differences are +acceptable; digest checks preserve existing published content, and retained +artifacts support retries requiring the same bytes. -**Viable alternative:** Declare a richer target variant including CPU features, -build tags, and other justified options, and encode variant identity in artifact -names, receipts, and manifests. That supports genuine hardware-specific products -correctly but adds public API and validation cost. Use it when such variants are -actual deliverables. Continuing to inherit unrecorded settings is not an equally -good alternative for a standardized release builder. +**Viable alternative:** A shared CI image can supply a centrally selected Go +version and build environment when this makes installation and support easier. +Maintainers own image updates; applications use the shared integration. This is +useful where a common environment reduces operational work. Its value should be +measured against image maintenance and the suite's differing Go requirements. +Explicit hardware variants can be added for a demonstrated product need. ### 3. Should the library own build-and-deliver, or accept only completed builds? -**Recommended:** Make declared tagged-source build-and-deliver the normal facade -operation, with source verification and temporary storage owned internally. -The CLI and Go callers then share one implementation. Retain prebuilt input only -if a real split-stage consumer needs it, with the current digest/source checks -and a clear lifecycle. A plain request struct and straightforward orchestration -are sufficient; no public state-machine framework is needed. +**Recommended:** Provide one facade operation for tagged-source verification, +selected-target builds, temporary storage, checksums, uploads, and cleanup. +Use it from the CLI so both interfaces share the procedure. Retain separate +building for local development and support prebuilt delivery where a concrete +handoff requirement justifies it. This minimizes consumer orchestration code. -**Viable alternative:** Keep `Build` and `Deliver` as the only primitives and -provide a canonical composition helper/example. This makes build environments -and credential isolation explicit and keeps the delivery operation narrow. -It is appropriate when most consumers intentionally hand artifacts between -separate stages, but asks ordinary Go callers to assemble more release logic. -For portable stage handoff, deliberately design a portable artifact description; -the current absolute-path receipt is intentionally local. +**Viable alternative:** Keep separate build and delivery primitives with a +maintained composition helper. This suits consumers that require credential +isolation between stages or need to retain artifacts for later delivery. Those +consumers accept responsibility for the artifact lifecycle in exchange for the +operational separation they need. ### 4. How should the shared executable and CI integration be distributed? -**Recommended:** A versioned shared CI runner/entry point, packaged with a known -ReleaseKit executable and compatible Go/Git environment, selected by immutable -image digest. Consumers provide the profile, selected image/toolchain, and secret -reference. Use one maintained flow for source-only and binary delivery. This -removes repeated installer/setup shell from applications and gives integration -fixes a versioned owner. It requires deliberately adopting image distribution, -which the current source-only release policy does not yet declare; local -maintainers can still install the versioned Go command. +**Recommended:** Choose the simplest maintained entry point for installation, +updates, and delivery. Begin with versioned source installation if it keeps +consumer integration small. Centralize reusable setup and provide one clear +upgrade procedure. Assess packaging by the consumer code and recurring developer +work it removes. -**Viable alternative:** Keep source-only tool distribution through pinned -`go install` and maintain a small canonical bootstrap/template. It needs less -hosting infrastructure and naturally supports different Go versions. Prefer -calling one combined delivery operation where credential isolation permits it. -The cost is repeated setup and template-update work in consumers; test the real -template and provide an explicit pin/update convention. Do not add executable -binary distribution merely to remove a few shell lines if this alternative -proves adequately small in adoption trials. +**Viable alternative:** Publish a maintained CI image containing ReleaseKit and +a compatible Go/Git environment when it substantially reduces setup. The image +provides a ready-to-run integration and centralizes environment maintenance. +It also creates an image publication and update responsibility, which should be +reflected in the release procedure. Either packaging choice should give +applications a small configuration and a routine invocation. -### 5. Are delivery result collections exclusive categories or overlapping views? +### 5. How should delivery results support simple recovery? -**Recommended:** Exclusive outcome categories, with pending meaning known work -remaining and uncertain meaning remote effect unresolved. A caller can render -or act on each category without deduplicating it against the others. Overall -state continues to prevent automatic retries after uncertain writes. +**Recommended:** Use exclusive outcome categories: matching, uploaded, known +pending, conflicting, and uncertain. Present ordinary callers with completion or +a clear failure and recovery instruction. Keep asset details available for +diagnostics. Consistent categories simplify implementation and interpretation. **Viable alternative:** Pending includes every unfinished declaration, with -conflicting/uncertain as diagnostic subsets. This can simplify a progress UI, -but must be defined explicitly and applied in every branch. Consumers must then -subtract blocked subsets before deriving retry work. Either is maintainable; -the present mixture is not. +conflicting/uncertain as diagnostic subsets. This can simplify a progress UI +when defined explicitly and applied in every branch. Consumers must then +subtract blocked subsets before deriving retry work. Apply the chosen +meaning consistently across all outcomes.