# ADR 0001: Own public contracts through facades ## Status Accepted. ## Date 2026-10-05 ## Context ReleaseKit is being designed as an opinionated Go library with a release executable. Its responsibilities include publication, cross-builds, version injection, and artifact delivery. Consuming applications also need lightweight access to the version embedded in their binaries. ConfigKit and PromptKit demonstrate a facade approach in which public packages own consumer contracts and delegate to internal implementation. This gives maintainers room to change internal structure while preserving supported type identity, method sets, and behavior. ReleaseKit needs that boundary from its first implementation. ## Decision The root `releasekit` package is the public facade for release orchestration. A separate public `buildinfo` package is the facade for runtime version information. Each package exposes a cohesive set of operations and values justified by consumer needs. Each facade defines its public named types and owns their documented behavior. Exported signatures, fields, callbacks, and method sets use facade-owned types and deliberately selected public dependencies. Handles retain implementation state in private fields and expose explicitly selected methods. Forwarding and conversion code translates between public contracts and internal representations. Implementation packages live under Go's `internal/` boundary. Dependency direction runs from public facades into internal implementation. Contracts shared between implementation packages belong inside that boundary. Git operations, Go toolchain execution, Gitea integration, and orchestration bookkeeping remain implementation responsibilities, with package layout chosen for cohesion. The `buildinfo` facade has a lightweight dependency graph suitable for application runtime imports. Its version accessor is a supported public contract. ReleaseKit's builder and runtime implementation own the linker symbol and injection mechanism together, allowing applications to obtain their version through the accessor. The release executable invokes the supported orchestration facade and owns command parsing, output, and exit codes. The library returns consumer-facing errors and outcomes that describe publication state, including partial progress and uncertainty. Go declarations and GoDoc own exact public API contracts. Additional public packages and extension interfaces require a deliberate decision grounded in a durable consumer need. Compiled-export and dependency checks protect facade ownership; external-package behavioral tests protect consumer semantics. ## Alternatives considered - Keep implementation in public packages: reduces forwarding work and makes implementation declarations part of the surface contributors must maintain. - Use aliases or embedded implementation types: reduces conversion code while coupling consumer type identity and method sets to implementation types. - Provide one facade for orchestration and runtime version access: offers one import path and a shared dependency graph for both responsibilities. - Expose a public package for each implementation component: enables direct component reuse and expands the compatibility surface across Git, build, and delivery machinery. ## Consequences Consumers depend on deliberate contracts in `releasekit` and `buildinfo`. Internal algorithms, collaborators, and package boundaries can evolve while those contracts remain stable. Both public packages participate in ReleaseKit's versioning and compatibility obligations. Explicit forwarding and conversions add maintenance work. They must preserve error identity, value ownership, callback lifetime, and observable outcomes. Boundary checks and representative consumer tests provide evidence for those properties as implementation proceeds. The separate `buildinfo` facade supports runtime use with a small dependency surface. Its integration with the builder requires tests that verify the selected release version is injected and reported correctly.