# Release tooling simplification Status: the selected release-tooling design has been implemented. All four generic file checks, registered-tool execution, page-only hosted delivery, and protection of the supplied token path are selected. The [completed implementation record](https://forge.maximumdirect.net/base-layer/commandkit/src/commit/87eb84ccb462bf54e6250c8b287ac217efe90883/docs/roadmap/implementation.md) contains stage order, tasks, validation, and completion evidence. Current release behavior stays with its canonical owners. ## Purpose and authority Reduce CommandKit's release infrastructure to declarative module profiles, a small launcher, and focused tests of CommandKit-owned wiring. Delegate reusable candidate validation and publication mechanics to ReleaseKit while retaining CommandKit's domain-specific checks in their existing owners. Add hosted Gitea release pages as a separate local delivery operation after source publication. The [agent policy](../policy/agents.md), [release policy](../policy/release.md#candidate-validation), and [testing policy](../policy/testing.md#upstream-integration-testing-ownership) govern implementation. The [release procedure](../release.md) continues to own the current workflow. ## Targeted end state ### Ownership CommandKit retains module selectors, product identities, profile locations, the authoritative endpoint selection, release order, release-note meaning, compatibility decisions, and attribution accuracy. Its existing public API, CLI, integration-adaptation, and consumer-example tests remain local and run through the owning module's suite. No parallel release-only domain suite is needed unless a concrete CommandKit requirement is otherwise unprotected. ReleaseKit supplies the standard offline candidate suite, selected generic file checks, candidate/note and publication guards, tag creation and publication, hosted delivery, outcome reporting, and recovery. CommandKit's launcher delegates those operations. Existing source-release completion and immutability rules continue to apply. Hosted pages are the added delivery channel; binary deliverables and platform support commitments remain unchanged. ### Profiles Select these existing ReleaseKit options in each profile: | Selection | Intended protection | | --- | --- | | `validation.go_format: true` | Detect unformatted committed Go source. | | `validation.markdown: {}` | Detect broken local Markdown destinations and supported heading fragments. | | `validation.module_distribution.workspace_files: true` | Detect committed development workspace files in selected inputs. | | `validation.module_distribution.local_replacements: true` | Detect filesystem replacements in selected committed module declarations. | Also select `validation.forbidden_files: [".releasekit/gitea-token"]` in all three profiles. This delegates protection of the supplied credential path to ReleaseKit's existing check. The path is repository-relative and the check applies across the captured repository even for an integration release. It does not read token contents, scan other paths, or inspect Git history. Retain the explicit shared-file lists and use ReleaseKit's existing input scope. The root profile does not run every nested module's suite. File checks inspect committed inputs and do not replace formatting worktree changes or reviewing documentation meaning, attribution, and external links. Markdown keeps its default treatment of outside-checkout destinations; no stricter boundary mode is proposed. The pinned [ReleaseKit configuration reference](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/23203f235cc414c4ffe0fd3941030eb0c9f9943f/docs/config.md) owns exact scope and behavior, including nested-module boundaries and vendored inputs. Do not expand an option's scope into a general repository prohibition. Race testing, full vet, compilation matrices, size limits, and additional forbidden-file paths are not selected by this roadmap. They can be considered separately for demonstrated needs. ### Launcher and recovery Use the root module's registered `go tool releasekit` through `exec`, keeping the current selector interface and publication argument mapping. Retain host normalization, workspace-off execution, the local toolchain, and read-only module metadata. Preserve other effective Go settings while arranging read-only selection. The implementation plan specifies the wrapper interface and invocation details. Go's cache supplies executable storage; the launcher creates no persistent binary directory. `/.releasekit/` remains ignored for the credential file, with an explanatory comment. Recovery instructions use the registered tool or the entry point printed for the saved attempt, preserving ReleaseKit's distinction between publication outcome and record-storage errors. Share module selection and host-safe tool invocation between publication, delivery, and recovery where applicable. Delivery selects the same module profile as publication; recovery uses its recorded attempt rather than inferring identity from a current profile. Keep the existing publication interface and provide an explicit delivery invocation without automatically chaining the two operations. Keep one selector mapping and shared invocation plumbing. ReleaseKit v0.9.0 shipped host-safe consumer launcher examples and regression coverage. The earlier simplification used v0.8.0, which already supported registered tools. Keep host normalization locally because the reviewed `go tool` invocation inherited foreign `GOOS`/`GOARCH` values and failed to run. Do not switch tool-version selection from the root module to each integration merely to match the upstream multi-module example. ### Hosted Gitea release pages Configure this delivery selection in each module profile: | Field | Selected value | | --- | --- | | `delivery.forge` | `gitea` | | `delivery.base_url` | `https://forge.maximumdirect.net` | | `delivery.owner` | `base-layer` | | `delivery.repository` | `commandkit` | | `delivery.token_file` | `.releasekit/gitea-token` | Preserve the profiles' distinct product identities and physical module directories. All pages belong to the same Gitea repository and are keyed by the complete tag: `vX.Y.Z` for core, `integrations/ckconfig/vX.Y.Z` for ckconfig, and `integrations/ckprompt/vX.Y.Z` for ckprompt. Pass the selected profile and semantic version to `deliver`; ReleaseKit derives the complete module tag. With no build targets, delivery is page-only. ReleaseKit uses the complete checked-in module release note, including its licensing footer, as the hosted body. No binary assets, receipts, or checksum manifests are added. Use current forge URLs and the full module tag for future notes' immutable source and licensing links. Existing published tags and notes remain unchanged. After source publication succeeds, explicitly invoke delivery from a clean checkout whose `HEAD` identifies that published tag's commit. For later retries, use the original tagged source and its recorded module files. Report the source publication outcome and hosted-delivery outcome separately, including the hosted URL on success. A delivery failure leaves the source release complete; repair delivery without republishing or moving its tag. Delivery performs its own read-only credential preflight, without rerunning candidate validation or publishing a tag. Hosted-service availability and the Gitea token do not become source-publication gates. A nonblank `RELEASEKIT_GITEA_TOKEN` environment value takes precedence over the configured file. The file path resolves from the repository root for all three modules. ReleaseKit accepts matching hosted content and reports conflicting content without overwriting it. Resolve uncertain hosted writes before retrying the same immutable version. The pinned [delivery guide](https://forge.maximumdirect.net/base-layer/releasekit/src/commit/23203f235cc414c4ffe0fd3941030eb0c9f9943f/docs/consumers/delivery.md) owns exact delivery behavior and recovery. Start with tags containing the new delivery configuration; historical page backfilling remains a separate decision. This local workflow needs no CI delivery job or additional secret distribution. ### Focused local tests Replace the release-test scaffolding with a small controlled Go-command boundary that invokes the actual launcher. Cover: - Selector-to-profile/module routing for core, ckconfig, and ckprompt, including consistency with the checked-in profiles' intended module and product. - Invalid argument handling before tool invocation. - Invocation from another directory and paths containing spaces. - Host normalization and workspace/toolchain/read-only settings. - Publication and delivery argument, output-stream, and child exit-status forwarding, with the selected module profile reaching the delivery operation. - Profile wiring for the shared Gitea destination, token path, and its selected committed-path protection; assertions do not read the credential file. Exercise module routing separately from exit statuses rather than multiplying every combination. Assert behavior and meaningful selections, not helper implementation details or exact usage prose. The resulting local suite omits the disposable publication exercise, generic tag inspection, assertion-helper self-tests, and custom build-call log/parser. Upstream publication and delivery coverage owns those generic behaviors. No replacement publication engine or exported test-helper API is needed. There is no line-count target for the replacement tests. ## Selected choices and rationale All four generic file checks are selected as release-time checks, in addition to the agreed forbidden token path. Formatting and local-link validation automate existing contributor review work. Workspace-file and filesystem-replacement checks address accidental inclusion of development metadata that a successful local test run can overlook. This adds specific release checks; it does not make every optional ReleaseKit validator mandatory or prohibit development workspaces and replacements outside the selected committed candidate inputs. Selecting only formatting and Markdown would change less release behavior, but would leave these distribution mistakes to manual review. The selected upstream checks avoid a second local implementation. Host-normalized registered-tool execution is selected because the root module already registers ReleaseKit and Go caches the executable. Retaining a persistent native executable would provide a recovery entry point independent of a later Go-driver invocation, but would retain executable-storage and bootstrap test maintenance. Recovery instead uses the registered tool or ReleaseKit's reported entry point. The credential directory remains ignored under either approach. The implementation plan records the existing integration dependency-version mismatch separately from validation of the current source. This infrastructure sprint does not publish releases or select new library dependency versions. Historical hosted-page backfilling and CI delivery remain separate future choices, not prerequisites for the selected local page-only workflow.