Prepare source release validation
This commit is contained in:
11
README.md
11
README.md
@@ -2,7 +2,7 @@
|
||||
|
||||
An opinionated Go library for applications that use YAML configuration files.
|
||||
|
||||
ConfigKit is in early implementation. Its current loader accepts one strict YAML
|
||||
ConfigKit's initial loader accepts one strict YAML
|
||||
source (or explicit defaults-only input), optionally traverses explicit path and glob
|
||||
imports, strictly composes their disjoint definitions, applies typed defaults, and
|
||||
can overlay one selected fixed profile and check an application schema version. It
|
||||
@@ -33,6 +33,9 @@ func ReadConfig(path string) (Config, error) {
|
||||
The [configuration contract](docs/config.md) describes implemented behavior. The
|
||||
[consumer adoption guide](docs/consumers/README.md) provides maintained Narratio-,
|
||||
Notarius-, WeatherReporter-, and Seriatim-shaped examples and migration guidance.
|
||||
The [initial target design](docs/roadmap/initial.md) describes planned behavior.
|
||||
The [implementation plan](docs/roadmap/implementation.md) owns the pending stages.
|
||||
See the [development guide](docs/development.md) for repository orientation.
|
||||
The [initial target record](docs/roadmap/initial.md) links implemented feature owners
|
||||
and preserves deliberately deferred scope. The [implementation plan](docs/roadmap/implementation.md)
|
||||
records completion evidence until release-candidate preparation retires it. See the
|
||||
[development guide](docs/development.md) for repository orientation and the
|
||||
[release procedure](docs/release.md) for maintainer-only candidate and publication
|
||||
steps.
|
||||
|
||||
@@ -20,8 +20,8 @@ Use distinct strict-composition and intentional-overlay operations. Composition
|
||||
rejects conflicting definitions; overlay provides explicit precedence. Keep the
|
||||
operations opinionated rather than adding arbitrary per-field merge strategies.
|
||||
The [architecture policy](../policy/architecture.md) owns the governing boundary;
|
||||
the [target design](../roadmap/initial.md#composition-and-overlay) owns the planned
|
||||
operation table until its current contract lands.
|
||||
the [current configuration contract](../config.md#strict-document-composition) owns
|
||||
the operation table and selected-profile overlay behavior.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ ConfigKit defines its supported YAML policy and keeps parser integration private
|
||||
Application types and diagnostics must not require parser-specific public types.
|
||||
Use a small internal boundary rather than a general parser/provider framework.
|
||||
The [architecture policy](../policy/architecture.md) owns this constraint; the
|
||||
[target design](../roadmap/initial.md#yaml-and-scalar-policy) owns planned syntax.
|
||||
[current YAML document](../config.md#yaml-documents) and
|
||||
[scalar](../config.md#scalars) contracts own the implemented syntax.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -22,8 +22,9 @@ values. Keep application defaults and normalization application-owned, but recor
|
||||
resolution changes so final inspection and metadata describe the actual resolved
|
||||
snapshot. Do not promise language-enforced immutability of exported Go values.
|
||||
The [architecture policy](../policy/architecture.md) owns these invariants; the
|
||||
[target design](../roadmap/initial.md#recorded-resolution-and-validation) owns the
|
||||
planned recording mechanism and ownership semantics.
|
||||
[current resolution contract](../config.md#recorded-application-resolution) and
|
||||
[ownership contract](../config.md#typed-projection-and-ownership) own the implemented
|
||||
recording mechanism and ownership semantics.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -21,8 +21,9 @@ Existing environment variables win even when empty. Report skipped files and
|
||||
partial failures without values. Keep bootstrap provenance separate from later
|
||||
lookup provenance rather than imply an unchanged environment between calls.
|
||||
General environment-variable configuration overlays are not on the roadmap.
|
||||
The [feature roadmap](../roadmap/initial.md#secret-references-and-explicit-bootstrap)
|
||||
owns the unimplemented contract; stages remain in the implementation plan.
|
||||
The [current reference contract](../config.md#typed-secret-references) and
|
||||
[bootstrap contract](../config.md#explicit-secrets-directory-bootstrap) own the
|
||||
implemented behavior.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@ node tree before typed decoding, retaining the existing parser adapter boundary.
|
||||
Recorded domain resolution follows input selection. Provide safe structured
|
||||
historical values and an explanation renderer in the initial release, building
|
||||
on ADR 0003's presence and audited resolution decision. Applications own commands.
|
||||
The [feature roadmap](../roadmap/initial.md#cli-overrides) owns the exact override
|
||||
contract and [explanation contract](../roadmap/initial.md#historical-value-explanation).
|
||||
The [current override contract](../config.md#explicit-cli-overrides) and
|
||||
[explanation contract](../config.md#historical-value-explanation) own the implemented
|
||||
behavior.
|
||||
|
||||
## Alternatives considered
|
||||
|
||||
|
||||
@@ -567,7 +567,7 @@ executes application methods or parser-specific hooks.
|
||||
|
||||
Exported struct fields use an explicit `yaml` name or the lowercase Go field name.
|
||||
Unexported fields and `yaml:"-"` are ignored. `omitempty` is accepted but does not
|
||||
change binding or future projection. An explicit `yaml:",inline"` flattens a struct
|
||||
change binding or projection. An explicit `yaml:",inline"` flattens a struct
|
||||
or pointer-to-struct, or designates at most one string-keyed inline map for otherwise
|
||||
unmatched names. Ambiguous names, named inline fields, multiple inline maps, and
|
||||
unsupported or malformed tag options are schema errors. Embedded fields are ordinary
|
||||
@@ -673,7 +673,7 @@ any sequence change reports the sequence path and never invents correspondence
|
||||
between old and new indices. Cross-kind and null/container changes replace the
|
||||
affected path.
|
||||
|
||||
These mechanisms currently support later decoding, resolution auditing, metadata,
|
||||
These mechanisms support decoding, resolution auditing, metadata,
|
||||
and rendering. They are not a public generic conversion or cloning API.
|
||||
|
||||
## Safe failures
|
||||
|
||||
@@ -81,9 +81,9 @@ WeatherReporter, or Seriatim. Updating those repositories, their deployed YAML,
|
||||
wiring, runtime catalogs, and operational documentation remains separate downstream
|
||||
work.
|
||||
|
||||
## Maintained roadmap examples
|
||||
## Maintained API examples
|
||||
|
||||
Every nontrivial API sketch from the feature roadmap has a compiled example or a
|
||||
Every nontrivial initial API sketch has a compiled example or a
|
||||
focused behavioral owner:
|
||||
|
||||
| Roadmap surface | Maintained owner |
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Development
|
||||
|
||||
This is the contributor entry point for ConfigKit. Read the task-specific owners
|
||||
below before making changes. The repository is in early implementation: its public
|
||||
below before making changes. Its public
|
||||
loader currently covers strict selected sources, explicit path/glob import graphs,
|
||||
composition, selected profile overlays, typed defaults, schema-version checks,
|
||||
explicit CLI overrides, recorded application resolution, semantic validation,
|
||||
@@ -23,10 +23,10 @@ redacted effective rendering and historical value explanation. The
|
||||
| --- | --- |
|
||||
| Repository orientation or component responsibility | [Architecture policy](policy/architecture.md) and [component overview](internal/overview.md) |
|
||||
| Documentation changes | [Documentation policy](policy/documentation.md) and the owning document |
|
||||
| Architecture decisions or future work | [Documentation policy](policy/documentation.md), [initial target design](roadmap/initial.md), and relevant ADRs listed below |
|
||||
| Architecture decisions or future work | [Documentation policy](policy/documentation.md), [initial target record](roadmap/initial.md), and relevant ADRs listed below |
|
||||
| Code and test changes | [Architecture policy](policy/architecture.md), [testing policy](policy/testing.md), and owning contracts/tests as they are introduced |
|
||||
| Examples or copyable assets | The owning implemented contract and [consumer adoption guide](consumers/README.md) |
|
||||
| Release preparation | [Release policy](policy/release.md) and [release-readiness gaps](roadmap/release-readiness.md); the operational runbook will be added before release |
|
||||
| Release preparation | [Release policy](policy/release.md), [release procedure](release.md), and [release-readiness evidence](roadmap/release-readiness.md) |
|
||||
|
||||
Accepted decisions:
|
||||
|
||||
|
||||
@@ -28,8 +28,8 @@ the owning implementation work extracts a symbol or case.
|
||||
- Use sanitized local fixtures only. Audio, transcripts, credentials, private
|
||||
configuration, and whole application package trees are application-only.
|
||||
- Record the exact copied/generalized symbols and tests in the owning section when
|
||||
extraction occurs. An entry below assigns evidence; it does not claim extraction
|
||||
or behavior is implemented.
|
||||
extraction occurs. Assignment prose records the original work boundary; dated
|
||||
implementation records state what was actually generalized.
|
||||
|
||||
## Narratio evidence
|
||||
|
||||
@@ -86,8 +86,8 @@ collection, conflict construction, and recursive mapping join in `compose.go` ad
|
||||
the assigned production symbols. `TestComposeDocumentsJoinsDisjointMappingsAndTracksClaims`,
|
||||
`TestComposeDocumentsRejectsEveryPresentNonMappingOverlap`, and
|
||||
`TestComposeDocumentsReportsAllClaimantsAtExactLocations` adapt the assigned cases.
|
||||
The planned empty-mapping difference is covered separately: empty mappings retain
|
||||
container provenance but contribute no child claims. No unplanned semantic deviation
|
||||
The intentional empty-mapping difference is covered separately: empty mappings retain
|
||||
container provenance but contribute no child claims. No other semantic deviation
|
||||
from the extracted additive composer was required.
|
||||
|
||||
### Imports
|
||||
@@ -122,9 +122,9 @@ declaration-order, disjoint composition, keyed-entry, all-source conflict, unsaf
|
||||
target, alias, imported parse/schema, and relative-resolution cases. ConfigKit adds
|
||||
recursive bounded DFS, `os.OpenRoot` confinement, canonical symlink identity,
|
||||
cycle/diamond route locations, optional-path semantics, aggregate budgets, and
|
||||
fragment version-placement enforcement. The planned glob syntax is parsed but
|
||||
remains explicitly unavailable for its next owning work; hard links intentionally
|
||||
replace Narratio's same-file rejection with path identity.
|
||||
fragment version-placement enforcement. That checkpoint parsed glob syntax behind an
|
||||
explicit unsupported gate that the subsequent glob implementation removed; hard
|
||||
links intentionally replace Narratio's same-file rejection with path identity.
|
||||
|
||||
Glob-import implementation record (2026-09-06): ConfigKit retains the extracted
|
||||
declaration order, import failures, composition, and identity cases while adding the
|
||||
@@ -133,7 +133,7 @@ new `expandImportGlob`, `readGlobMatches`, and pattern-validation mechanisms in
|
||||
directories, hard links, contained and escaping symlinks, unmatched declarations,
|
||||
malformed and recursive patterns, escaped metacharacters, character classes,
|
||||
permission failures, explicit `conf.d` use, and entry/candidate budgets. This work
|
||||
has no Narratio production equivalent; it uses the planned standard-library
|
||||
has no Narratio production equivalent; it uses the selected standard-library
|
||||
`path.Match` and bounded `File.ReadDir` adaptation rather than its flat loader.
|
||||
|
||||
### Profiles and overlay
|
||||
@@ -199,8 +199,8 @@ inspection cases across one default/import/profile/resolution workflow. ConfigKi
|
||||
adds chronological descendant history for parent and whole-sequence operations,
|
||||
composite empty-mapping origins, canonical resolution reasons/dependencies, private
|
||||
snapshot agreement, defensive nested copies, and concurrent load isolation. Value
|
||||
rendering, redaction, explanation, commands, generated attribution, diffs, and
|
||||
digests remain assigned to their later owning work.
|
||||
That checkpoint deliberately left rendering, redaction, explanation, commands,
|
||||
generated attribution, diffs, and digests outside its scope.
|
||||
|
||||
Effective-rendering implementation record (2026-09-06): ConfigKit adapts Narratio's
|
||||
deterministic effective-output and side-effect-free inspection cases in
|
||||
@@ -212,7 +212,8 @@ resolved values, text-scalar snapshot reuse, application YAML-hook isolation,
|
||||
non-disclosure through failures and record formatting, caller mutation, and writer
|
||||
failures. Unlike Narratio's marshal/reparse path, ConfigKit renders only its owned
|
||||
frozen tree and substitutes redaction before the upstream dumper boundary. Historical
|
||||
value explanation and secret references remain assigned to later work.
|
||||
value explanation and secret references were implemented at their later owning
|
||||
boundaries and are exercised by the consumer startup example below.
|
||||
|
||||
### Defaults, presence, and domain resolution
|
||||
|
||||
|
||||
@@ -20,17 +20,17 @@ module and package documentation boundary. Its implemented public primitives are
|
||||
- a per-operation private reflection descriptor graph in `schema.go` for supported
|
||||
types, YAML field binding, inlining, secret tags, recursion, and semantic paths;
|
||||
- descriptor-driven canonical projection, detached typed cloning, cycle/limit
|
||||
enforcement, and structural comparison in `projection.go`; and
|
||||
enforcement, and structural comparison in `projection.go`;
|
||||
- strict schema-driven decoding over detached defaults in `decode.go`, including
|
||||
mapping/sequence semantics, null and numeric policy, safe codec errors, presence,
|
||||
baseline/final trees, and initial default/input origins; and
|
||||
baseline/final trees, and initial default/input origins;
|
||||
- public lifecycle coordination in `load.go`, bounded canonical import DFS in
|
||||
`imports.go`, pattern-directed glob expansion in `glob.go`, version-report contexts
|
||||
in `validation.go`, and detached layered metadata/history assembly in
|
||||
`load_metadata.go`; and
|
||||
`load_metadata.go`;
|
||||
- recorded application defaulting and normalization in `resolution.go`, including
|
||||
explicitness queries, helper verification, structural mutation audit, coalesced
|
||||
intent, private before/after snapshots, and resolution metadata integration; and
|
||||
intent, private before/after snapshots, and resolution metadata integration;
|
||||
- post-resolution schema-aware report collection and validator mutation detection in
|
||||
`validation.go`, completing the public callback lifecycle after composed input;
|
||||
- opaque typed environment references and per-load name resolution in
|
||||
@@ -38,13 +38,15 @@ module and package documentation boundary. Its implemented public primitives are
|
||||
validator-state auditing;
|
||||
- explicit bounded startup environment bootstrap and safe partial reporting in
|
||||
`secrets.go`;
|
||||
- fixed-point tag/predicate/dependency sensitivity classification in `secret.go`; and
|
||||
- fixed-point tag/predicate/dependency sensitivity classification in `secret.go`;
|
||||
- frozen-snapshot redaction and canonical effective output in `render.go`;
|
||||
- bounded immutable input applications, safe historical replay, detached explanation
|
||||
records, and deterministic human rendering in `explain.go`, with the
|
||||
only upstream dumper integration isolated in `internal/yaml/write.go`; and
|
||||
only upstream dumper integration isolated in `internal/yaml/write.go`;
|
||||
- a separate maintained `examples/consumers` package with four sanitized consumer
|
||||
shapes, fixtures, domain validators, and runtime-boundary functions.
|
||||
shapes, fixtures, domain validators, and runtime-boundary functions; and
|
||||
- a fail-fast source-candidate checker in `scripts/release-check.sh`, with local
|
||||
documentation-link and public import-boundary gates owned by root-package tests.
|
||||
|
||||
The [configuration contract](../config.md) owns implemented input, schema, decoding,
|
||||
loading lifecycle, path imports, composition, profile/CLI overlay, version checking,
|
||||
@@ -54,15 +56,13 @@ explanation, and ownership behavior.
|
||||
The [consumer adoption guide](../consumers/README.md) owns current application-fit
|
||||
and migration guidance.
|
||||
|
||||
The source-extraction inventory records the application foundations assigned to
|
||||
future implementation work:
|
||||
The source-extraction inventory records the application foundations used by the
|
||||
implementation:
|
||||
|
||||
- [Extraction inventory](extraction.md)
|
||||
|
||||
This document will inventory additional components and link to their current
|
||||
contracts and focused internal documentation as they are introduced.
|
||||
|
||||
The [architecture policy](../policy/architecture.md) owns binding boundaries and
|
||||
invariants. The [initial target design](../roadmap/initial.md) describes planned
|
||||
behavior; it is not an inventory of implemented features. See the
|
||||
[development guide](../development.md) for contributor orientation and validation.
|
||||
invariants. The [initial target record](../roadmap/initial.md) links current feature
|
||||
owners and preserves deferred scope; it is not an implementation inventory. See the
|
||||
[development guide](../development.md) for contributor orientation and validation
|
||||
and the [release procedure](../release.md) for source-candidate gates.
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
## Purpose and applicability
|
||||
|
||||
ConfigKit is an opinionated Go library for consistent YAML configuration loading
|
||||
and resolution across consuming applications. This policy governs contributions
|
||||
now; it does not claim that the target features are implemented. The
|
||||
[component overview](../internal/overview.md) owns implementation inventory and
|
||||
[initial roadmap](../roadmap/initial.md) owns unimplemented target behavior.
|
||||
and resolution across consuming applications. This policy governs contributions.
|
||||
The [component overview](../internal/overview.md) owns implementation inventory, the
|
||||
[configuration contract](../config.md) owns implemented behavior, and the
|
||||
[initial target record](../roadmap/initial.md) preserves deferred scope.
|
||||
|
||||
## Success criteria
|
||||
|
||||
@@ -48,8 +48,8 @@ existing primitives cannot accommodate it cleanly, and show how the extension
|
||||
preserves a coherent model. Application-specific interpretation and validation
|
||||
remain appropriate. Reuse Narratio's applicable infrastructure under these
|
||||
boundaries, and keep simple consumers independent of optional composition
|
||||
features. The [consumer API design](../roadmap/initial.md#consumer-api-design)
|
||||
describes the proposed surface; this policy does not claim it is implemented.
|
||||
features. The [consumer adoption guide](../consumers/README.md) demonstrates the
|
||||
implemented surface against representative simple and complex shapes.
|
||||
|
||||
## Responsibility boundaries
|
||||
|
||||
@@ -103,12 +103,12 @@ decoding. Preserve presence and source information through processing. Ordinary
|
||||
values must not be used to infer whether input was absent. Final configuration,
|
||||
metadata, and effective inspection must agree, including application resolution
|
||||
changes; see [ADR 0003](../adr/0003-preserve-presence-and-resolution-history.md).
|
||||
Safe historical values and an explanation renderer belong to the initial target,
|
||||
Safe historical values and an explanation renderer are part of the implemented contract,
|
||||
including superseded/deleted paths and effective source attribution. Inspection
|
||||
must agree with the final typed snapshot and apply historical sensitivity rules.
|
||||
See [ADR 0005](../adr/0005-explicit-overrides-and-safe-explanation.md).
|
||||
Detailed syntax and operation tables belong to the target roadmap until their
|
||||
current configuration contract is implemented.
|
||||
Detailed syntax and operation tables belong to the
|
||||
[current configuration contract](../config.md).
|
||||
|
||||
## Ownership and confidentiality
|
||||
|
||||
@@ -136,6 +136,7 @@ for safe messages supplied by their hooks.
|
||||
Do not introduce automatic directory discovery, network providers, arbitrary
|
||||
merge strategies, additional configuration languages, or application runtime
|
||||
management without concrete consumer evidence and an explicit design decision.
|
||||
The roadmap owns the complete deferred-feature inventory. Significant boundary
|
||||
The [initial target record](../roadmap/initial.md#explicit-non-goals-and-deferred-scope)
|
||||
owns the deferred-feature inventory. Significant boundary
|
||||
changes require an ADR and corresponding policy/contract updates; implementation
|
||||
convenience alone is not a reason to broaden the public API.
|
||||
|
||||
@@ -62,24 +62,24 @@ handling, not secret values.
|
||||
| Documentation rules | `docs/policy/documentation.md` | Ownership and document lifecycle |
|
||||
| Testing rules | `docs/policy/testing.md` | Risk-based sufficiency, test boundaries, and maintenance principles |
|
||||
| Release rules | `docs/policy/release.md` | Compatibility, integrity, gates, immutability, and exceptions |
|
||||
| Release procedure | `docs/release.md`, when operational | Exact maintainer commands, prerequisites, supported targets, and verification |
|
||||
| Release procedure | `docs/release.md` | Exact maintainer commands, prerequisites, supported targets, and verification |
|
||||
| Exported Go API | Go documentation beside declarations | Symbol contracts, errors, ownership, and lifecycle API behavior |
|
||||
| YAML and resolution semantics | `docs/config.md`, as behavior lands | Syntax, composition, precedence, conversion, secret references/bootstrap, and explanation semantics; Go reference docs link here for shared rules |
|
||||
| Consumer walkthroughs | `docs/consumers/`, when useful | Task-oriented usage and consumer responsibilities, not duplicate API reference |
|
||||
| Component inventory | `docs/internal/overview.md` | Implemented components and links to their owners |
|
||||
| Component mechanics | Other `docs/internal/` files, when needed | Detailed implementation behavior and change recipes |
|
||||
| Architectural decisions | `docs/adr/` | Context, decisions, alternatives, consequences, and supersession history |
|
||||
| Initial target | `docs/roadmap/initial.md` | Unimplemented end-state and deferred feature scope |
|
||||
| Initial target record | `docs/roadmap/initial.md` | Implemented-feature owner links and deferred feature scope until roadmap retirement |
|
||||
| Implementation plan | `docs/roadmap/implementation.md` | Stages, dependencies, acceptance gates, and progress |
|
||||
| Release readiness gaps | `docs/roadmap/release-readiness.md` | Outstanding release prerequisites and closure evidence |
|
||||
| Release readiness evidence | `docs/roadmap/release-readiness.md` | Closed preparation gaps and outstanding candidate/publication evidence until roadmap retirement |
|
||||
| Historical release notes | `docs/releases/` | Version-specific historical summaries required by release policy |
|
||||
| Complete examples | `examples/` and executable Go examples | Maintained artifacts; prose links instead of duplicating full examples |
|
||||
|
||||
A listed future owner is not a requirement to create an empty file now. Create
|
||||
API, consumer, example, and component documents when the corresponding behavior
|
||||
A listed owner is not a requirement to create an empty file before it has useful
|
||||
content. Create API, consumer, example, and component documents when the corresponding behavior
|
||||
exists and there is useful content to own. Link only to existing files; use plain
|
||||
code paths for planned files. Release prerequisites have the explicit temporary
|
||||
exception recorded in the release policy.
|
||||
code paths for planned files. Unvalidated candidate and publication work has the
|
||||
explicit temporary exception recorded in the release policy.
|
||||
|
||||
ConfigKit has no owned HTTP service, application CLI, or runtime operations
|
||||
interface. Do not create those reference documents for consuming applications.
|
||||
|
||||
@@ -222,17 +222,21 @@ restating or redefining its requirements.
|
||||
|
||||
### Temporary bootstrap deferral
|
||||
|
||||
The release procedure (`docs/release.md`) and complete release-check command are
|
||||
not yet present because ConfigKit has no Go module or implementation to validate.
|
||||
Their creation is temporarily deferred during initial development. This exception
|
||||
permits implementation work; it does not permit publishing a release without
|
||||
any gate required above.
|
||||
The release procedure and automated source-candidate checker now exist, but no exact
|
||||
release candidate, version-matched release note, native macOS execution evidence, or
|
||||
post-publication module retrieval has been validated. Initial implementation may be
|
||||
completed without fabricating those later facts. This exception does not authorize
|
||||
publication or waive any candidate, platform, remote, or consumer-verification gate.
|
||||
|
||||
Compensating controls: no release may be published until the
|
||||
[release-readiness gaps](../roadmap/release-readiness.md) are closed, the runbook
|
||||
and checker exist, and the exact candidate passes all applicable gates. The
|
||||
maintainer preparing the first release owns closure. Remove this temporary
|
||||
exception when readiness is verified. Any other exception requires a documented repository constraint, rationale,
|
||||
Compensating controls: the [release procedure](../release.md) keeps every unvalidated
|
||||
step as an explicit maintainer gate, and the
|
||||
[release-readiness evidence](../roadmap/release-readiness.md) records what is closed
|
||||
and outstanding. No release may be published until an exact committed candidate has
|
||||
the required release note, passes all applicable automated and native-platform gates,
|
||||
is verified against `origin/main`, and completes guarded tag publication and clean
|
||||
consumer retrieval. The maintainer preparing the first release owns closure. Remove
|
||||
this temporary exception when that evidence is recorded and obsolete roadmap files
|
||||
are retired. Any other exception requires a documented repository constraint, rationale,
|
||||
compensating controls, scope, and closure condition here; none is currently
|
||||
adopted. Do not silently weaken the base integrity, validation, documentation,
|
||||
verification, or immutability guarantees.
|
||||
|
||||
@@ -39,7 +39,7 @@ boundaries. No credential bytes may appear in inspection or failure fixtures'
|
||||
expected output; use disposable canaries to prove non-disclosure.
|
||||
|
||||
Baseline commands belong in the [development guide](../development.md). Release
|
||||
gates belong in the [release policy](release.md) and its eventual runbook. This
|
||||
gates belong in the [release policy](release.md) and [maintainer runbook](../release.md). This
|
||||
policy does not imply that those tools or tests already exist.
|
||||
|
||||
## Every test has a cost
|
||||
|
||||
240
docs/release.md
Normal file
240
docs/release.md
Normal file
@@ -0,0 +1,240 @@
|
||||
# ConfigKit Release Procedure
|
||||
|
||||
This is the maintainer runbook for ConfigKit's [release policy](policy/release.md).
|
||||
ConfigKit publishes one source-only Go module: the immutable source tag and the
|
||||
matching checked-in release note are the deliverables. There is no application
|
||||
binary, container image, generated package, or separate registry publication.
|
||||
|
||||
## Release identity and support
|
||||
|
||||
- Module: `gitea.maximumdirect.net/eric/ConfigKit`
|
||||
- Primary branch: `main`
|
||||
- Authoritative remote: `origin`, expected to fetch from
|
||||
`https://gitea.maximumdirect.net/eric/ConfigKit.git`
|
||||
- Tags: stable Semantic Versions such as `v0.1.0`; prerelease tags are not supported
|
||||
- Minimum Go language/toolchain line: Go 1.25, tested with a supported patched
|
||||
Go 1.25 toolchain and one newer supported toolchain
|
||||
- Build targets: Linux and macOS on amd64 and arm64
|
||||
|
||||
The automated checker cross-builds all four targets. Before release, the maintainer
|
||||
must also obtain native test, race, symlink, and permission-fixture evidence on Linux
|
||||
and macOS; cross-compilation is not native execution evidence.
|
||||
|
||||
## 1. Prepare access and tools
|
||||
|
||||
The release maintainer owns this procedure. Work in a dedicated clone with Git, Bash,
|
||||
and two supported Go toolchains available. Configure private-host Git and Go module
|
||||
access through the normal credential manager before starting. Keep tokens, passwords,
|
||||
SSH material, and environment dumps outside the repository and command transcript.
|
||||
Verify access without displaying credentials:
|
||||
|
||||
```sh
|
||||
git remote get-url origin
|
||||
git ls-remote origin HEAD
|
||||
```
|
||||
|
||||
The remote URL must equal the authoritative URL above. Select the latest supported
|
||||
patch in the Go 1.25 line and a newer supported toolchain. The values below are the
|
||||
toolchains used while this runbook was introduced; update them to supported patch
|
||||
releases during candidate preparation and record the actual versions in the release
|
||||
note or validation record.
|
||||
|
||||
```sh
|
||||
export CONFIGKIT_BASELINE_TOOLCHAIN=go1.25.5
|
||||
export CONFIGKIT_NEWER_TOOLCHAIN=go1.26.7
|
||||
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go version
|
||||
GOTOOLCHAIN="$CONFIGKIT_NEWER_TOOLCHAIN" go version
|
||||
GOTOOLCHAIN="$CONFIGKIT_BASELINE_TOOLCHAIN" go mod download
|
||||
GOTOOLCHAIN="$CONFIGKIT_NEWER_TOOLCHAIN" go mod download
|
||||
```
|
||||
|
||||
Those commands explicitly acquire toolchains and dependencies. The checker itself
|
||||
sets `GOPROXY=off` and fails if its required cache is incomplete.
|
||||
|
||||
## 2. Select the version and review compatibility
|
||||
|
||||
Choose an unused stable version and compare the candidate with the previous tag.
|
||||
For the first release, review the whole public surface and current contracts.
|
||||
|
||||
```sh
|
||||
release_version=v0.1.0
|
||||
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
||||
git show-ref --verify --quiet "refs/tags/$release_version" && exit 1 || :
|
||||
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
|
||||
printf 'remote tag already exists: %s\n' "$release_version" >&2
|
||||
exit 1
|
||||
else
|
||||
test $? -eq 2
|
||||
fi
|
||||
git log --oneline --decorate --no-merges
|
||||
```
|
||||
|
||||
Review exported Go signatures and ownership, YAML and scalar behavior, precedence,
|
||||
diagnostic codes, minimum Go version, and platform support. Before `v1.0.0`, any
|
||||
intentional incompatible minor-release change must be explained with consumer action;
|
||||
patch releases must remain compatible within their minor line. Review the maintained
|
||||
consumer examples and the migration guide even when signatures did not change.
|
||||
|
||||
Reassess `go.yaml.in/yaml/v4` rather than using `@latest` implicitly:
|
||||
|
||||
```sh
|
||||
go list -m -versions go.yaml.in/yaml/v4
|
||||
go list -m -json go.yaml.in/yaml/v4@latest
|
||||
```
|
||||
|
||||
If changing the explicit pin, make that a reviewed dependency change and rerun the
|
||||
complete checker, especially parser policy, limits, diagnostics, and rendering tests.
|
||||
If retaining a prerelease pin, record that decision in Compatibility.
|
||||
|
||||
## 3. Write the release note
|
||||
|
||||
Create `docs/releases/$release_version.md` before selecting the candidate. It must
|
||||
begin with `# ConfigKit $release_version` and contain `Summary`, `Compatibility`,
|
||||
`Upgrade`, and `Changes` sections. Use “No action required” where appropriate. Link
|
||||
to current canonical contracts instead of copying their definitions. Do not create a
|
||||
release note until there is a real candidate and reviewed content.
|
||||
|
||||
## 4. Validate the source candidate
|
||||
|
||||
Run the complete checker from the repository root after dependencies have been
|
||||
acquired. It validates module manifests in a disposable copy, both supported Go
|
||||
toolchains, offline default tests, the native race detector, vet, native builds,
|
||||
CGO-disabled cross-builds, formatting and whitespace (including untracked files),
|
||||
examples, package isolation, and local documentation links.
|
||||
|
||||
```sh
|
||||
./scripts/release-check.sh
|
||||
```
|
||||
|
||||
`go vet` is the repository's static-analysis baseline. No additional linter is
|
||||
claimed. Links to current ConfigKit files and headings are strict. Recorded links to
|
||||
sibling consumer source are checked when those checkouts exist and are otherwise
|
||||
inapplicable in an isolated clone; their immutable revisions remain recorded in the
|
||||
extraction inventory.
|
||||
|
||||
Complete these manual gates and record their evidence with the candidate:
|
||||
|
||||
- The maintainer reviews compatibility and downstream migration impact against
|
||||
`docs/config.md`, Go API comments, and the consumer guide.
|
||||
- The maintainer inspects `git status --short`, `git diff`, and the candidate file
|
||||
list for credentials, private data, generated output, unintended files, and
|
||||
unrelated changes.
|
||||
- The maintainer records successful native checker runs on Linux and macOS, including
|
||||
filesystem capability tests. If either host is unavailable, release remains
|
||||
blocked unless platform support is formally narrowed in current documentation.
|
||||
- The maintainer removes completed, obsolete documents under `docs/roadmap/`, repairs
|
||||
inbound links, and reruns the checker. ADR rationale remains historical.
|
||||
- The maintainer reviews the exact version-matched release note for accuracy and
|
||||
confirms it describes only deliverables that will actually be published.
|
||||
|
||||
## 5. Commit, push, and record the candidate
|
||||
|
||||
Commit all candidate source, contract, example, roadmap-retirement, and release-note
|
||||
changes, rerun the checker against that clean commit, then push only `main` and record
|
||||
the exact commit in Git metadata local to the clone:
|
||||
|
||||
```sh
|
||||
git add .
|
||||
git commit --message "Prepare ConfigKit $release_version"
|
||||
./scripts/release-check.sh
|
||||
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
||||
git push origin HEAD:refs/heads/main
|
||||
git rev-parse HEAD | tee .git/configkit-release-candidate
|
||||
candidate_commit=$(cat .git/configkit-release-candidate)
|
||||
```
|
||||
|
||||
If review changes the source after this point, create and validate a new candidate;
|
||||
do not reuse the recorded commit.
|
||||
|
||||
## 6. Run publication guards
|
||||
|
||||
Immediately before tagging, fetch the authoritative branch and tags, restore the
|
||||
recorded variables if this is a new shell, and execute every guard:
|
||||
|
||||
```sh
|
||||
release_version=v0.1.0
|
||||
candidate_commit=$(cat .git/configkit-release-candidate)
|
||||
git fetch --prune origin main
|
||||
git fetch --tags origin
|
||||
test "$(git branch --show-current)" = main
|
||||
test -z "$(git status --porcelain=v1 --untracked-files=all)"
|
||||
test "$(git rev-parse HEAD)" = "$candidate_commit"
|
||||
test "$(git rev-parse refs/remotes/origin/main)" = "$candidate_commit"
|
||||
test "$(git remote get-url origin)" = 'https://gitea.maximumdirect.net/eric/ConfigKit.git'
|
||||
printf '%s\n' "$release_version" | grep -Eq '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
|
||||
test -f "docs/releases/$release_version.md"
|
||||
test "$(sed -n '1p' "docs/releases/$release_version.md")" = "# ConfigKit $release_version"
|
||||
for heading in Summary Compatibility Upgrade Changes; do
|
||||
grep -Fxq "## $heading" "docs/releases/$release_version.md"
|
||||
done
|
||||
git show-ref --verify --quiet "refs/tags/$release_version" && exit 1 || :
|
||||
if git ls-remote --exit-code --tags origin "refs/tags/$release_version" >/dev/null; then
|
||||
printf 'remote tag already exists: %s\n' "$release_version" >&2
|
||||
exit 1
|
||||
else
|
||||
test $? -eq 2
|
||||
fi
|
||||
```
|
||||
|
||||
Confirm the recorded automated and manual approvals apply to exactly
|
||||
`$candidate_commit`. A successful older run is not evidence for a changed commit.
|
||||
|
||||
## 7. Tag and publish the exact ref
|
||||
|
||||
Create one annotated tag at the guarded commit, verify its peeled target, and push
|
||||
only that ref. Do not use `git push --tags`.
|
||||
|
||||
```sh
|
||||
git tag --annotate "$release_version" --message "ConfigKit $release_version" "$candidate_commit"
|
||||
test "$(git rev-list -n 1 "$release_version")" = "$candidate_commit"
|
||||
git push origin "refs/tags/$release_version:refs/tags/$release_version"
|
||||
```
|
||||
|
||||
The pushed tag completes the declared source-only publication. No Gitea release
|
||||
object or binary upload is required.
|
||||
|
||||
## 8. Verify publication and clean consumer retrieval
|
||||
|
||||
Verify the authoritative tag and then retrieve that exact version into a new module
|
||||
without a local `replace` directive. Private-host credentials must already be
|
||||
configured. Use direct origin retrieval unless an explicitly approved internal Go
|
||||
proxy is the publication channel.
|
||||
|
||||
```sh
|
||||
remote_tag_commit=$(git ls-remote origin "refs/tags/$release_version^{}" | awk '{print $1}')
|
||||
test "$remote_tag_commit" = "$candidate_commit"
|
||||
consumer_dir=$(mktemp -d)
|
||||
(
|
||||
cd "$consumer_dir"
|
||||
go mod init example.invalid/configkit-release-check
|
||||
GOPRIVATE=gitea.maximumdirect.net GOPROXY=direct go get "gitea.maximumdirect.net/eric/ConfigKit@$release_version"
|
||||
cat > main.go <<'EOF'
|
||||
package main
|
||||
|
||||
import configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||
|
||||
func main() {
|
||||
_ = configkit.NoSource()
|
||||
}
|
||||
EOF
|
||||
gofmt -w main.go
|
||||
go test ./...
|
||||
go build ./...
|
||||
go list -m -f '{{.Path}} {{.Version}}' gitea.maximumdirect.net/eric/ConfigKit
|
||||
)
|
||||
rm -rf -- "$consumer_dir"
|
||||
```
|
||||
|
||||
The final `go list` output must show the exact module path and `$release_version`.
|
||||
Record the result with the release evidence.
|
||||
|
||||
## 9. Handle failures without replacement
|
||||
|
||||
Before publication, fix the candidate, rerun every gate, commit, push, and record a
|
||||
new exact candidate. An unpublished local tag may be deleted only after verifying it
|
||||
was never pushed or used by another release channel.
|
||||
|
||||
After publication, never move, delete, or recreate the tag and never replace its
|
||||
release note. Correct the defect on `main`, choose a new semantically appropriate
|
||||
version, and repeat this procedure. A supported advisory or deprecation mechanism
|
||||
may warn consumers about the old version but cannot change its contents.
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Status and ownership
|
||||
|
||||
Status: implementation in progress; Stages 1–15 are complete and later stages are
|
||||
pending.
|
||||
Status: implementation complete; Stages 1–22 are complete. Release-candidate
|
||||
selection and publication remain separate maintainer work.
|
||||
|
||||
Audience: a `gpt-5.6-terra` coding agent implementing one stage per prompt, in
|
||||
ascending order. Each stage depends on every earlier stage being complete.
|
||||
@@ -85,7 +85,7 @@ the adapter, YAML-policy, diagnostics, limits, and rendering regressions. A fina
|
||||
upstream version is preferred when it passes those checks; if the RC is retained,
|
||||
record that decision in release readiness and compatibility review.
|
||||
|
||||
Follow the feature's [upstream isolation contract](initial.md#yaml-dependency-and-public-api-isolation).
|
||||
Follow the feature's [upstream isolation contract](../policy/architecture.md#public-api-and-dependency-direction).
|
||||
Translate upstream API changes internally without changing ConfigKit declarations
|
||||
or consumer requirements. Never re-export upstream aliases/options/plugins, expose
|
||||
parser errors through wrapping, or pass parser-created objects through `any`.
|
||||
@@ -97,8 +97,8 @@ unverified upstream versions or add a selectable-parser framework.
|
||||
### Updated extraction map
|
||||
|
||||
Use the source revisions and adaptation policies owned by the feature's
|
||||
[foundation](initial.md#existing-implementation-foundation) and
|
||||
[secret bootstrap](initial.md#secret-references-and-explicit-bootstrap) sections.
|
||||
[foundation](../internal/extraction.md) and
|
||||
[secret bootstrap](../config.md#typed-secret-references) sections.
|
||||
Paths below are relative to the named sibling repository. Reinspect them in
|
||||
Stage 1 and record the exact revision actually copied. The maintainer is the sole
|
||||
author of the relevant application code and has authorized its reuse and relicensing
|
||||
@@ -154,9 +154,9 @@ syscall-level confinement, path discovery, or a public filesystem-provider API.
|
||||
|
||||
### Secret, override, and history implementation bounds
|
||||
|
||||
Follow the feature contracts for [secrets](initial.md#secret-references-and-explicit-bootstrap),
|
||||
[CLI overrides](initial.md#cli-overrides), and
|
||||
[explanation](initial.md#historical-value-explanation). Introduce these public APIs
|
||||
Follow the feature contracts for [secrets](../config.md#typed-secret-references),
|
||||
[CLI overrides](../config.md#explicit-cli-overrides), and
|
||||
[explanation](../config.md#historical-value-explanation). Introduce these public APIs
|
||||
only in Stages 16–19. Earlier stages cover ordinary types and file/profile layers;
|
||||
they must not expose an unresolved secret as a completed load or silently accept
|
||||
an override option. Extend the shared descriptor/projection graph for `Secret`
|
||||
@@ -303,8 +303,8 @@ Completion evidence (2026-09-06):
|
||||
No deviations were required. Paths, diagnostics, parsing, and all later behavior
|
||||
remain assigned to subsequent stages.
|
||||
|
||||
Read: feature [foundation](initial.md#existing-implementation-foundation),
|
||||
[consumer fit](initial.md#consumer-fit-and-intentional-migrations), all policies.
|
||||
Read: feature [foundation](../internal/extraction.md),
|
||||
[consumer fit](../consumers/README.md), all policies.
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -353,8 +353,8 @@ Completion evidence (2026-09-06):
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
metadata population and configuration lifecycle behavior remain later work.
|
||||
|
||||
Read: feature [paths](initial.md#paths-and-presence),
|
||||
[diagnostics](initial.md#provenance-diagnostics-and-redaction), public metadata API.
|
||||
Read: feature [paths](../config.md#layered-metadata),
|
||||
[diagnostics](../config.md#safe-failures), public metadata API.
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -408,8 +408,8 @@ Completion evidence (2026-09-06):
|
||||
`go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64. No
|
||||
deviations were required; typed binding and decoding remain later work.
|
||||
|
||||
Read: feature [YAML policy](initial.md#yaml-and-scalar-policy),
|
||||
[source constructors](initial.md#entry-point-and-reusable-application-definition).
|
||||
Read: feature [YAML policy](../config.md#yaml-documents),
|
||||
[source constructors](../config.md#single-source-loading).
|
||||
|
||||
Start with the extraction map's parser and strict-loader cases; the old
|
||||
second-document acceptance defect is already fixed in Narratio.
|
||||
@@ -485,8 +485,8 @@ Completion evidence (2026-09-06):
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
typed value operations remain later work.
|
||||
|
||||
Read: feature [typed decoding](initial.md#typed-decoding) and
|
||||
[type/projection contract](initial.md#supported-types-and-projection).
|
||||
Read: feature [typed decoding](../config.md#defaults-and-typed-decoding) and
|
||||
[type/projection contract](../config.md#application-schema-binding).
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -537,8 +537,8 @@ Completion evidence (2026-09-06):
|
||||
Go 1.26.7 on linux/amd64. No deviations were required; defaults and typed decoding
|
||||
remain later work.
|
||||
|
||||
Read: feature [ownership](initial.md#recorded-resolution-and-validation) and
|
||||
[type/projection contract](initial.md#supported-types-and-projection).
|
||||
Read: feature [ownership](../config.md#recorded-application-resolution) and
|
||||
[type/projection contract](../config.md#application-schema-binding).
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -590,7 +590,7 @@ Completion evidence (2026-09-06):
|
||||
and `git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
public loading and schema-version checks remain later work.
|
||||
|
||||
Read: feature [defaults/null](initial.md#static-defaults-and-null) and typed decoding.
|
||||
Read: feature [defaults/null](../config.md#defaults-and-typed-decoding) and typed decoding.
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -651,9 +651,9 @@ Completion evidence (2026-09-06):
|
||||
`go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64. No
|
||||
deviations were required; resolution and semantic validation remain later work.
|
||||
|
||||
Read: feature [lifecycle](initial.md#resolution-lifecycle),
|
||||
[version hook](initial.md#schema-checking-and-secret-classification),
|
||||
[results](initial.md#results-errors-and-inspection).
|
||||
Read: feature [lifecycle](../config.md#single-source-loading),
|
||||
[version hook](../config.md#application-schema-binding),
|
||||
[results](../config.md#safe-failures).
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -715,7 +715,7 @@ Completion evidence (2026-09-06):
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
semantic validation remains later work.
|
||||
|
||||
Read: feature [resolution callbacks](initial.md#resolution-and-validation-callbacks).
|
||||
Read: feature [resolution callbacks](../config.md#recorded-application-resolution).
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -776,8 +776,8 @@ Completion evidence (2026-09-06):
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
imports and profiles remain deliberately unavailable.
|
||||
|
||||
Read: feature [diagnostic callbacks](initial.md#resolution-and-validation-callbacks)
|
||||
and [schema reports](initial.md#schema-checking-and-secret-classification).
|
||||
Read: feature [diagnostic callbacks](../config.md#recorded-application-resolution)
|
||||
and [schema reports](../config.md#application-schema-binding).
|
||||
|
||||
Tasks:
|
||||
|
||||
@@ -824,7 +824,7 @@ Completion evidence (2026-09-06):
|
||||
[current composition contract](../config.md#strict-document-composition) owns the
|
||||
implemented semantics; public import wiring remains deferred to subsequent work.
|
||||
|
||||
Read: feature [composition table](initial.md#composition-and-overlay).
|
||||
Read: feature [composition table](../config.md#strict-document-composition).
|
||||
|
||||
Extract Narratio's additive composer and conflict tests before writing equivalent
|
||||
code. Change empty-map expectations to the feature table and retain exact locations.
|
||||
@@ -883,7 +883,7 @@ Completion evidence (2026-09-06):
|
||||
`go test -race ./...`, `go vet ./...`, `go build ./...`, `go mod tidy -diff`, and
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64.
|
||||
|
||||
Read: feature [import graph](initial.md#explicit-imports-and-source-identity).
|
||||
Read: feature [import graph](../config.md#explicit-imports).
|
||||
|
||||
Extract the flat import loader and tests, then generalize its graph, identity and
|
||||
containment rules. Do not treat its root-only declarations as ConfigKit's contract.
|
||||
@@ -1008,7 +1008,7 @@ Completion evidence (2026-09-06):
|
||||
Verified `go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`,
|
||||
and `git diff --check` with Go 1.26.7 on linux/amd64.
|
||||
|
||||
Read: feature [profiles](initial.md#profiles), composition/overlay table.
|
||||
Read: feature [profiles](../config.md#selected-profiles), composition/overlay table.
|
||||
|
||||
Extract Narratio's overlay mechanics and profile tests; preserve the intentional
|
||||
null/kind and profile-selection differences listed in the feature roadmap.
|
||||
@@ -1064,8 +1064,8 @@ Completion evidence (2026-09-06):
|
||||
Verified `go test ./...`, `go test -race ./...`, `go vet ./...`, `go build ./...`,
|
||||
`go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on linux/amd64.
|
||||
|
||||
Read: feature [presence](initial.md#paths-and-presence),
|
||||
[history](initial.md#provenance-diagnostics-and-redaction), metadata API.
|
||||
Read: feature [presence](../config.md#layered-metadata),
|
||||
[history](../config.md#safe-failures), metadata API.
|
||||
|
||||
Use Narratio's effective ownership and inspection tests as extraction evidence.
|
||||
Its source-only records need locations and complete historical operations.
|
||||
@@ -1123,8 +1123,8 @@ Completion evidence (2026-09-06):
|
||||
`go build ./...`, `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on
|
||||
linux/amd64.
|
||||
|
||||
Read: feature [redaction](initial.md#provenance-diagnostics-and-redaction),
|
||||
[secret predicate](initial.md#schema-checking-and-secret-classification), result API.
|
||||
Read: feature [redaction](../config.md#safe-failures),
|
||||
[secret predicate](../config.md#application-schema-binding), result API.
|
||||
|
||||
Reuse Narratio's deterministic effective-output and non-disclosure cases. Render
|
||||
from the owned typed projection, without its marshal/parse reconstruction.
|
||||
@@ -1195,7 +1195,7 @@ Completion evidence (2026-09-06):
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
environment-backed typed secret references remain later work.
|
||||
|
||||
Read: [secret bootstrap contract](initial.md#secret-references-and-explicit-bootstrap),
|
||||
Read: [secret bootstrap contract](../config.md#typed-secret-references),
|
||||
architecture responsibility boundary, testing policy, and WeatherReporter's
|
||||
`internal/config/secrets.go` and corresponding `config_test.go` cases; also
|
||||
Narratio's `internal/app/secrets_env.go`, its tests, and bounded-read helper.
|
||||
@@ -1267,7 +1267,7 @@ Completion evidence (2026-09-06):
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
CLI overrides remain later work.
|
||||
|
||||
Read: [secret reference contract](initial.md#secret-references-and-explicit-bootstrap),
|
||||
Read: [secret reference contract](../config.md#typed-secret-references),
|
||||
shared descriptor/projection rules and lifecycle, Stage 16 report boundary.
|
||||
|
||||
Tasks:
|
||||
@@ -1337,7 +1337,7 @@ Completion evidence (2026-09-06):
|
||||
`git diff --check` with Go 1.26.7 on linux/amd64. No deviations were required;
|
||||
safe historical-value explanation remains later work.
|
||||
|
||||
Read: [override contract](initial.md#cli-overrides), overlay/presence/version rules,
|
||||
Read: [override contract](../config.md#explicit-cli-overrides), overlay/presence/version rules,
|
||||
source ordering, and the secret-reference boundary.
|
||||
|
||||
Tasks:
|
||||
@@ -1403,7 +1403,7 @@ Completion evidence (2026-09-06):
|
||||
`go build ./...`, `go mod tidy -diff`, and `git diff --check` with Go 1.26.7 on
|
||||
linux/amd64. No deviations were required; consumer ergonomics remain later work.
|
||||
|
||||
Read: [explanation contract](initial.md#historical-value-explanation), redaction
|
||||
Read: [explanation contract](../config.md#historical-value-explanation), redaction
|
||||
rules, and history bounds above.
|
||||
|
||||
Generalize Narratio's semantic-record and inspection tests. They cover effective
|
||||
@@ -1598,7 +1598,47 @@ Acceptance:
|
||||
|
||||
## Stage 22 — Prepare release validation and reconcile documentation
|
||||
|
||||
Status: pending.
|
||||
Status: complete.
|
||||
|
||||
Completion evidence (2026-09-06):
|
||||
|
||||
- Added the [maintainer release procedure](../release.md) for the existing
|
||||
`origin/main`, module `gitea.maximumdirect.net/eric/ConfigKit`, source-only stable
|
||||
tags, Go 1.25 minimum and newer-toolchain validation, and Linux/macOS amd64/arm64
|
||||
targets. It supplies candidate recording, clean branch/index/worktree and exact
|
||||
remote-commit guards, version/release-note/tag checks, precise single-ref tag
|
||||
publication, clean consumer retrieval without `replace`, and immutable correction
|
||||
steps. Private-host access is a prerequisite without embedding credentials or
|
||||
environment dumps.
|
||||
- Added fail-fast [`scripts/release-check.sh`](../../scripts/release-check.sh). It
|
||||
verifies cached dependencies and runs offline disposable-copy module hygiene,
|
||||
default tests on Go 1.25.5 and Go 1.26.7, vet and native builds on both, a native
|
||||
race run, CGO-disabled builds for linux/amd64, linux/arm64, darwin/amd64, and
|
||||
darwin/arm64, repository-wide Go formatting and text whitespace including
|
||||
untracked files, executable examples, consumer fixtures, public import isolation,
|
||||
and local documentation links. Toolchain/dependency acquisition remains an
|
||||
explicit preceding runbook step.
|
||||
- Added `TestLocalDocumentationLinks`, which strictly verifies repository-local files
|
||||
and Markdown headings while treating recorded sibling-source links as applicable
|
||||
only when those optional checkouts exist. The runbook makes immutable extraction
|
||||
revisions authoritative in isolated release clones.
|
||||
- Reconciled README, development, configuration, consumer, architecture/testing/
|
||||
documentation/release policies, component and extraction inventories, and ADR
|
||||
navigation with current behavior. Reduced the implemented feature roadmap to a
|
||||
target record linking current owners and retaining only foundations plus explicit
|
||||
non-goals/deferred scope. The implementation plan and readiness record remain until
|
||||
an actual candidate retires completed roadmap files as required by release policy.
|
||||
- Reassessed the YAML v4 dependency with `go list -m -versions` and
|
||||
`go list -m -json ...@latest`; `v4.0.0-rc.6` remained the newest available release
|
||||
on 2026-09-06, so the tested explicit pin was retained. `go doc -all` and
|
||||
`TestDependencyImportBoundary` confirmed public documentation is renderable and no
|
||||
upstream YAML type/import leaks outside the private adapter or maintained examples.
|
||||
- The complete checker passed on linux/amd64 with Go 1.25.5 and Go 1.26.7. The
|
||||
[release-readiness evidence](release-readiness.md) keeps exact candidate/release
|
||||
note, native macOS execution, compatibility/content approval, roadmap retirement,
|
||||
authoritative remote/tag guards, and post-publication retrieval explicitly open
|
||||
under the revised bootstrap exception. No tag, push, downstream migration, release
|
||||
note, or publication occurred.
|
||||
|
||||
Read: release policy in full and [release-readiness gaps](release-readiness.md).
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,24 +2,36 @@
|
||||
|
||||
## Status and ownership
|
||||
|
||||
ConfigKit is not release-ready. This document tracks outstanding release
|
||||
prerequisites under the [temporary bootstrap exception](../policy/release.md#temporary-bootstrap-deferral).
|
||||
It is not the library implementation plan and does not assign implementation
|
||||
stages. The maintainer preparing the first release owns closure.
|
||||
ConfigKit's implementation is prepared for release-candidate validation, but no
|
||||
release candidate has been selected or publication authorized. The maintainer
|
||||
preparing the first release owns the remaining gates under the
|
||||
[temporary bootstrap exception](../policy/release.md#temporary-bootstrap-deferral).
|
||||
This evidence record remains until candidate preparation retires completed roadmap
|
||||
material in favor of the operational [release procedure](../release.md) and normal
|
||||
release notes.
|
||||
|
||||
## Outstanding prerequisites
|
||||
## Preparation evidence
|
||||
|
||||
| Gap | Evidence required to close |
|
||||
| Preparation item | Status and evidence |
|
||||
| --- | --- |
|
||||
| No Go module or declared support matrix | Established module path, supported Go versions and platform targets documented in the release procedure |
|
||||
| No release runbook | `docs/release.md` exists with the prerequisites, commands, publication guards, and verification required by release policy |
|
||||
| No complete release checker | A documented command exists and exercises every applicable automated candidate gate; manual gates and inapplicable checks are explicit |
|
||||
| No consumer verification procedure | Runbook verifies retrieval of the exact released module version and a representative consumer build without local replacement directives |
|
||||
| No verified secret/precedence/explanation contracts | Current contracts and passing bootstrap skip/partial-failure, secret isolation, CLI precedence, and safe historical-value regressions; representative consumer examples |
|
||||
| No validated release candidate | Version-matched release note, current contracts/examples, and complete checks against the exact committed candidate |
|
||||
| Module and support matrix | Closed: the runbook records module `gitea.maximumdirect.net/eric/ConfigKit`, minimum Go 1.25 with a patched 1.25 plus newer supported toolchain, and Linux/macOS on amd64/arm64. |
|
||||
| Maintainer release procedure | Closed: `docs/release.md` owns access prerequisites, candidate recording, complete validation, exact remote/commit/tag guards, source-only publication, consumer retrieval, and correction. |
|
||||
| Automated source checker | Closed for current-source preparation: `scripts/release-check.sh` passed on 2026-09-06 with Go 1.25.5 and Go 1.26.7 on linux/amd64. It performs disposable-copy module hygiene, cached/offline tests, race, vet, native and four-target cross-builds, formatting/whitespace, examples, import isolation, and local-link gates. The exact candidate must rerun it. |
|
||||
| Consumer verification procedure | Closed as procedure: the runbook retrieves an exact published version into a clean temporary module with no local replacement and tests/builds it. Actual retrieval remains a post-publication gate. |
|
||||
| Secret/precedence/explanation evidence | Closed locally: current contracts and deterministic tests cover bootstrap skip/partial failure, credential isolation, defaults/base/profile/CLI precedence, historical redaction, and maintained consumer startup examples. |
|
||||
| Parser dependency reassessment | Closed for preparation: on 2026-09-06, `go list -m -versions go.yaml.in/yaml/v4` and `go list -m -json go.yaml.in/yaml/v4@latest` both showed `v4.0.0-rc.6` as the newest available release. The explicit pin is retained; a candidate compatibility review must reassess and record it again. |
|
||||
|
||||
No release can proceed while these prerequisites remain open. Close items only
|
||||
on evidence from actual files and checks, not proposed commands. Record closure
|
||||
evidence here while this roadmap remains active. Once all gaps are closed,
|
||||
remove the bootstrap exception and retire this document in favor of the
|
||||
operational runbook and normal release records.
|
||||
## Outstanding release gates
|
||||
|
||||
| Gate | Owner and closure evidence |
|
||||
| --- | --- |
|
||||
| Exact candidate and release note | Maintainer selects an unused stable version, writes `docs/releases/<version>.md`, commits all release changes, runs the checker against that exact clean commit, pushes it to `origin/main`, and records the commit. |
|
||||
| Native platform execution | Maintainer records applicable checker, race, symlink, and permission-fixture results on native Linux and macOS. Current local evidence is Linux/amd64 only; cross-builds do not close macOS execution. |
|
||||
| Compatibility, migration, and content review | Maintainer records public API/configuration/diagnostic review, downstream migration impact, release-note approval, and inspection for credentials, private data, generated output, unintended files, and unrelated changes. |
|
||||
| Roadmap retirement | Maintainer removes obsolete completed files under `docs/roadmap/`, repairs inbound links, and reruns the checker as part of the candidate. This record and the implementation plan intentionally remain while no candidate exists. |
|
||||
| Remote publication guards | Maintainer fetches authoritative `origin/main` and tags immediately before publication and proves branch, clean worktree/index, candidate commit, remote commit, release note, approvals, and unused version all agree. |
|
||||
| Tag and retrieval verification | After authorization, maintainer pushes only the exact immutable source tag, verifies its peeled remote commit, and retrieves/tests/builds the exact version in a clean consumer module without `replace`. |
|
||||
|
||||
No tag, push, downstream migration, release note, or release publication was
|
||||
performed during implementation. A green local checker does not close the exact
|
||||
candidate, native macOS, remote, or post-publication gates.
|
||||
|
||||
151
documentation_test.go
Normal file
151
documentation_test.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package configkit
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
var markdownLinkPattern = regexp.MustCompile(`(?m)(?:^|[[:space:]])\[[^\]]*\]\(([^)[:space:]]+)`)
|
||||
|
||||
func TestLocalDocumentationLinks(t *testing.T) {
|
||||
repository, err := filepath.Abs(".")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var failures []string
|
||||
err = filepath.WalkDir(repository, func(path string, entry os.DirEntry, walkErr error) error {
|
||||
if walkErr != nil {
|
||||
return walkErr
|
||||
}
|
||||
if entry.IsDir() {
|
||||
if entry.Name() == ".git" {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if filepath.Ext(path) != ".md" {
|
||||
return nil
|
||||
}
|
||||
content, readErr := os.ReadFile(path)
|
||||
if readErr != nil {
|
||||
return readErr
|
||||
}
|
||||
for _, match := range markdownLinkPattern.FindAllStringSubmatch(string(content), -1) {
|
||||
target := strings.Trim(match[1], "<>")
|
||||
if strings.Contains(target, "://") || strings.HasPrefix(target, "mailto:") {
|
||||
continue
|
||||
}
|
||||
filePart, fragment, _ := strings.Cut(target, "#")
|
||||
decoded, decodeErr := url.PathUnescape(filePart)
|
||||
if decodeErr != nil {
|
||||
failures = append(failures, fmt.Sprintf("%s: invalid escaped link %q", relativePath(repository, path), target))
|
||||
continue
|
||||
}
|
||||
linked := path
|
||||
if decoded != "" {
|
||||
linked = filepath.Clean(filepath.Join(filepath.Dir(path), filepath.FromSlash(decoded)))
|
||||
}
|
||||
_, statErr := os.Stat(linked)
|
||||
outside := linked != repository && !strings.HasPrefix(linked, repository+string(filepath.Separator))
|
||||
if os.IsNotExist(statErr) && outside && optionalSiblingSource(repository, linked) {
|
||||
continue // Recorded sibling-source links are optional in isolated clones.
|
||||
}
|
||||
if statErr != nil {
|
||||
failures = append(failures, fmt.Sprintf("%s: missing local link %q", relativePath(repository, path), target))
|
||||
continue
|
||||
}
|
||||
if fragment != "" && filepath.Ext(linked) == ".md" && !markdownHasFragment(linked, fragment) {
|
||||
failures = append(failures, fmt.Sprintf("%s: missing fragment in %q", relativePath(repository, path), target))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(failures) != 0 {
|
||||
t.Fatalf("documentation link failures:\n%s", strings.Join(failures, "\n"))
|
||||
}
|
||||
}
|
||||
|
||||
func optionalSiblingSource(repository, linked string) bool {
|
||||
relative, err := filepath.Rel(filepath.Dir(repository), linked)
|
||||
if err != nil || relative == "." || filepath.IsAbs(relative) {
|
||||
return false
|
||||
}
|
||||
parts := strings.Split(filepath.ToSlash(relative), "/")
|
||||
if len(parts) == 0 {
|
||||
return false
|
||||
}
|
||||
switch strings.ToLower(parts[0]) {
|
||||
case "narratio", "notarius", "weatherreporter", "seriatim":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func markdownHasFragment(path, wanted string) bool {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer file.Close()
|
||||
wanted, err = url.PathUnescape(wanted)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
seen := make(map[string]int)
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if !strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
heading := strings.TrimSpace(strings.TrimLeft(line, "#"))
|
||||
base := markdownFragment(heading)
|
||||
count := seen[base]
|
||||
seen[base]++
|
||||
fragment := base
|
||||
if count > 0 {
|
||||
fragment = fmt.Sprintf("%s-%d", base, count)
|
||||
}
|
||||
if fragment == wanted {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func markdownFragment(heading string) string {
|
||||
var result strings.Builder
|
||||
previousSpace := false
|
||||
for _, character := range strings.ToLower(heading) {
|
||||
switch {
|
||||
case unicode.IsLetter(character), unicode.IsDigit(character), character == '_', character == '-':
|
||||
result.WriteRune(character)
|
||||
previousSpace = false
|
||||
case unicode.IsSpace(character):
|
||||
if result.Len() > 0 && !previousSpace {
|
||||
result.WriteByte('-')
|
||||
previousSpace = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return strings.TrimRight(result.String(), "-")
|
||||
}
|
||||
|
||||
func relativePath(root, path string) string {
|
||||
relative, err := filepath.Rel(root, path)
|
||||
if err != nil {
|
||||
return path
|
||||
}
|
||||
return filepath.ToSlash(relative)
|
||||
}
|
||||
75
scripts/release-check.sh
Executable file
75
scripts/release-check.sh
Executable file
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repository_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$repository_dir"
|
||||
|
||||
baseline_toolchain=${CONFIGKIT_BASELINE_TOOLCHAIN:?set CONFIGKIT_BASELINE_TOOLCHAIN to a cached supported Go 1.25 patch release}
|
||||
newer_toolchain=${CONFIGKIT_NEWER_TOOLCHAIN:?set CONFIGKIT_NEWER_TOOLCHAIN to a cached newer supported Go toolchain}
|
||||
|
||||
run_go() {
|
||||
local toolchain=$1
|
||||
shift
|
||||
GOTOOLCHAIN="$toolchain" GOPROXY=off go "$@"
|
||||
}
|
||||
|
||||
check_toolchain() {
|
||||
local toolchain=$1
|
||||
GOTOOLCHAIN="$toolchain" GOPROXY=off go version >/dev/null
|
||||
run_go "$toolchain" mod download
|
||||
}
|
||||
|
||||
check_toolchain "$baseline_toolchain"
|
||||
check_toolchain "$newer_toolchain"
|
||||
bash -n scripts/release-check.sh
|
||||
|
||||
temporary_dir=$(mktemp -d)
|
||||
trap 'rm -rf -- "$temporary_dir"' EXIT
|
||||
git ls-files --cached --others --exclude-standard -z |
|
||||
tar --null --files-from=- --create --file=- |
|
||||
tar --extract --file=- --directory="$temporary_dir"
|
||||
(
|
||||
cd "$temporary_dir"
|
||||
GOTOOLCHAIN="$baseline_toolchain" GOPROXY=off go mod tidy
|
||||
)
|
||||
diff -u go.mod "$temporary_dir/go.mod"
|
||||
diff -u go.sum "$temporary_dir/go.sum"
|
||||
|
||||
mapfile -d '' go_files < <(git ls-files --cached --others --exclude-standard -z -- '*.go')
|
||||
if ((${#go_files[@]})); then
|
||||
unformatted=$(gofmt -l -- "${go_files[@]}")
|
||||
if [[ -n "$unformatted" ]]; then
|
||||
printf 'gofmt required for:\n%s\n' "$unformatted" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
git diff --check HEAD --
|
||||
while IFS= read -r -d '' candidate_file; do
|
||||
case "$candidate_file" in
|
||||
*.go|*.md|*.sh|go.mod|go.sum|LICENSE|.gitignore|AGENTS.md)
|
||||
if LC_ALL=C grep -nE '[[:blank:]]+$' -- "$candidate_file"; then
|
||||
printf 'trailing whitespace found in %s\n' "$candidate_file" >&2
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done < <(git ls-files --cached --others --exclude-standard -z)
|
||||
|
||||
for toolchain in "$baseline_toolchain" "$newer_toolchain"; do
|
||||
run_go "$toolchain" test ./...
|
||||
run_go "$toolchain" vet ./...
|
||||
run_go "$toolchain" build ./...
|
||||
done
|
||||
|
||||
run_go "$newer_toolchain" test -race ./...
|
||||
run_go "$newer_toolchain" test . -run '^Example'
|
||||
run_go "$newer_toolchain" test ./examples/consumers
|
||||
run_go "$newer_toolchain" test . -run '^TestLocalDocumentationLinks$'
|
||||
run_go "$newer_toolchain" test . -run '^TestDependencyImportBoundary$'
|
||||
|
||||
for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64; do
|
||||
target_os=${target%/*}
|
||||
target_arch=${target#*/}
|
||||
GOTOOLCHAIN="$newer_toolchain" GOPROXY=off CGO_ENABLED=0 GOOS="$target_os" GOARCH="$target_arch" go build ./...
|
||||
done
|
||||
Reference in New Issue
Block a user