diff --git a/README.md b/README.md index 9a096a1..7dc4253 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ An opinionated Go library for applications that use YAML configuration files. -ConfigKit is in pre-implementation. This repository currently contains its design -and contributor policies; no usable Go library has been implemented yet. +ConfigKit is in early implementation. The Go module and root package boundary are +established, but no usable configuration loader has been implemented yet. The [initial target design](docs/roadmap/initial.md) describes planned behavior. The [implementation plan](docs/roadmap/implementation.md) owns the pending stages. diff --git a/doc.go b/doc.go new file mode 100644 index 0000000..61d146e --- /dev/null +++ b/doc.go @@ -0,0 +1,7 @@ +// Package configkit will provide deterministic, application-owned configuration +// loading for Go programs. +// +// The package currently establishes the ConfigKit module boundary only. Loading, +// decoding, composition, provenance, and inspection APIs will be introduced with +// their implemented contracts; no usable configuration loader is available yet. +package configkit diff --git a/docs/development.md b/docs/development.md index 4efc662..49472ee 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,9 +1,10 @@ # Development This is the contributor entry point for ConfigKit. Read the task-specific owners -below before making changes. The repository is in pre-implementation: it has no -Go module, packages, tests, or executable examples yet. The -[component overview](internal/overview.md) owns the implementation inventory. +below before making changes. The repository is in early implementation: it has a +Go module and documented root package, but no loading behavior or executable +examples yet. The [component overview](internal/overview.md) owns the implementation +inventory. ## Initial orientation @@ -34,25 +35,34 @@ Accepted decisions: For cross-cutting changes, follow every applicable row. The [implementation plan](roadmap/implementation.md) owns the ordered stages and their -acceptance checks; all remain pending until implementation evidence is recorded. +acceptance checks and recorded implementation evidence. ## Baseline validation -For the current documentation-only repository: +Install Go 1.25.0 or a supported patched/newer Go toolchain. Acquire declared +dependencies explicitly before entering an offline development or validation +environment: ```sh +go mod download +``` + +Run the library baseline from the repository root: + +```sh +go test ./... +go vet ./... +go build ./... git diff --check ``` -Also inspect new untracked documents, verify changed local links and heading -fragments, and review paths, examples, ownership, and current-versus-planned -claims. The command above does not check links or untracked content. - -Go validation is not runnable until a module and packages exist. The scaffolding -change must establish and verify library test, vet, and build commands here, -including their prerequisites. Do not use an application binary build as the -library baseline. Add executable-example and other checks when those artifacts -are introduced; do not document nonexistent tools as operational. +The default tests must remain deterministic and runnable without network access or +credentials after dependency acquisition. Also inspect new untracked files, verify +changed local links and heading fragments, and review paths, examples, ownership, +and current-versus-planned claims. The commands above do not check links or +untracked content. Do not use an application binary build as the library baseline. +Add executable-example and other checks when those artifacts are introduced; do +not document nonexistent tools as operational. Once code exists, use focused checks while iterating and validation proportionate to the change under the testing policy. Documentation-only work does not require diff --git a/docs/internal/extraction.md b/docs/internal/extraction.md new file mode 100644 index 0000000..b8a8f65 --- /dev/null +++ b/docs/internal/extraction.md @@ -0,0 +1,242 @@ +# Source Extraction Inventory + +This inventory records reusable implementation evidence from sibling applications. +Those checkouts are review inputs only: ConfigKit does not import them, and its +build and tests must not require them. ConfigKit's current contracts and roadmap +govern every adaptation. + +## Inspected revisions + +| Application | Revision | Worktree | Role | +| --- | --- | --- | --- | +| Narratio | `b68435128be1e24b94fc7ec259d6e9093669fd99` | Clean `main` tracking `origin/main` | Primary parsing, composition, import, profile, presence, defaults, resolution, and inspection source | +| WeatherReporter | `5d306a202471e10fe98923a1df27d0b0fce5c666` | Clean `main` tracking `origin/main` | Secrets bootstrap and simple-consumer/defaults/options evidence | + +These revisions were inspected on 2026-09-06. Paths below are relative to each +application repository. Record later source revisions and adaptations here when +the owning implementation work extracts a symbol or case. + +## Adaptation rules + +- Copy and generalize only the smallest applicable mechanism or behavioral case. +- Replace upstream YAML nodes, application types, commands, logging, digests, and + provider registries with ConfigKit-owned boundaries. +- Preserve strictness, deterministic behavior, and useful failure coverage while + changing expectations that conflict with ConfigKit's accepted contracts. +- 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. + +## Narratio evidence + +### Source parsing and strict input + +Assigned to the YAML/source implementation: + +- Production: `internal/config/load.go` functions `decodeStrictYAML`, + `decodeStrictYAMLFromReader`, and `LoadSessionBytesWithOptions`; and + `internal/config/composition.go` functions `parseCompositionDocument`, + `parseCompositionBytes`, and `buildCompositionNode`. +- Cases: `TestLoadersRejectTrailingYAMLDocuments`, + `TestStrictYAMLRejectsParserExposedEmptyTrailingDocument`, and + `TestStrictYAMLAcceptsSingleDocumentAndRejectsUnknownFields` in + `internal/config/loader_strict_test.go`; plus duplicate-key, alias, non-mapping, + malformed-input, scalar spelling, presence, declaration-order, and source-label + coverage in `TestParseCompositionDocumentRetainsPresenceOwnershipAndDeclarationOrder` + and `TestParseCompositionDocumentRejectsAmbiguousOrMalformedYAML`. +- Preserve: labeled reader/byte input, strict unknown-field intent, rejection of + trailing documents (including an empty second document), duplicate detection, + and source-aware failures. +- Adapt: translate v4 parser nodes into ConfigKit's private document tree, apply + ConfigKit's scalar grammar and limits, and replace raw parser errors with safe + diagnostics. Narratio's application decoders and YAML node types are not copied. + +### Strict composition + +Assigned to document composition: + +- Production: `mergeAdditiveComposition`, `mergeAdditiveCompositions`, + `validateAdditiveClaims`, `appendCompositionClaims`, `mergeAdditiveNodes`, + `newCompositionConflict`, and cloning/path/source helpers in + `internal/config/composition.go`. +- Cases: `TestMergeAdditiveCompositionJoinsOnlyDisjointMappings`, + `TestMergeAdditiveCompositionRejectsEveryDuplicateClass`, and + `TestMergeAdditiveCompositionReportsAllClaimingSources`. +- Preserve: recursive joining of disjoint mappings, collisions for every overlapping + non-mapping value (including equal values and sequences), all claimant sources, + deterministic traversal, and nonmutation of inputs. +- Adapt: empty mappings follow ConfigKit's no-child operation rule; paths use the + ConfigKit semantic path model; both precise locations and composite origins are + retained. Default values never participate in strict composition. + +### Imports + +Assigned to explicit import traversal and glob handling: + +- Production: `loadPipelineCompositionSources`, + `splitPipelineCompositionEnvelope`, `loadPipelineImports`, and related ownership + structures in `internal/config/pipeline_composition.go`. +- Cases: `TestSplitPipelineCompositionEnvelopePreservesInputAndDeclarationOrder`, + `TestSplitPipelineCompositionEnvelopeRejectsMalformedShapesWithoutMutation`, + `TestLoadPipelineCompositionImportsDisjointFieldsAndTracksOwnership`, + `TestLoadPipelineCompositionMergesDisjointKeyedEntries`, + `TestLoadPipelineCompositionRejectsBaseConflictsWithAllSources`, + `TestLoadPipelineCompositionRejectsUnsafeOrInvalidImports`, + `TestLoadPipelineCompositionRejectsSameFileAliasesAndImportedComposition`, + `TestLoadPipelineCompositionReportsImportedParseAndSchemaSources`, and + `TestLoadPipelineCompositionKeepsRelativePathsRootBased`. +- Preserve: explicit declarations, declaration-order traversal, disjoint + composition, conflict attribution, malformed/unreadable target failures, directive + removal, and imported parse/schema source labels. +- Adapt: replace the root-only `composition` envelope with recursive + `_configkit.imports`; add path and glob declarations, bounded depth-first graph + traversal, canonical containment, cycle/diamond routes, and fixed source IDs. + Canonical paths—not `os.SameFile`—define identity, so hard links remain distinct. + +### Profiles and overlay + +Assigned to selected-profile overlay: + +- Production: `mergeOverlayComposition`, `mergeOverlayNodes`, + `selectPipelineProfile`, `loadPipelineProfileOverlays`, and + `loadedProfileOverlay`. +- Cases: `TestLoadPipelineProfilesSelectDefaultAndExplicitOverlay`, + `TestLoadPipelineProfileSelectionErrors`, + `TestPipelineProfileNamesRejectControlCharacters`, + `TestLoadPipelineProfilesValidateEveryDeclaredOverlay`, + `TestLoadPipelineProfileOverlaySemantics`, + `TestLoadPipelineProfileRejectsNullAndKindChanges`, and + `TestLoadPipelineProfilePairResolvesIndependentEffectivePipelines`. +- Preserve: recursive mapping overlay, atomic scalar/sequence replacement, + deterministic selection failures, source ownership, and independent results. +- Adapt: load only the selected fixed profile path; lowercase `default` means no + overlay. ConfigKit permits null and cross-kind replacement and does not support + declared defaults, inheritance, arbitrary profile paths, or validating every + unselected overlay. + +### Effective inspection and provenance + +Assigned to layered metadata, redaction, rendering, and explanation: + +- Production: `EffectivePipelineValues`, `EffectivePipelineSources`, + `MarshalEffectivePipeline`, `effectivePipelineFieldPaths`, + `effectivePipelineOwners`, and composition `semanticRecords`/ + `compactSemanticRecords`. +- Cases: `TestCompositionCanonicalOutputsAreDeterministic`, + `TestEffectivePipelineValuesIgnoreEquivalentSourceLayout`, + `TestConfigValidateAndShowPipelineOnlyAreSideEffectFree`, + `TestConfigSourcesReportsStableOwnership`, + `TestConfigSourcesReportsCanonicalFamilyAndPublishOrigins`, + `TestConfigSourcesPreservesProfileOwnershipThroughFamilyExpansion`, and + `TestConfigSourcesReportsRootImportProfileAndDefaultOwnership`. +- Preserve: deterministic effective projection, stable logical paths, source + ownership, side-effect-free inspection, and domain-attribution evidence. +- Adapt: project directly from ConfigKit-owned typed values without YAML round trips; + add line/column locations, composite origins, complete operation history, detached + records, and redaction. Narratio commands, diff/digest APIs, generated artifact + attribution, campaign logic, and party expansion remain application-owned. + +### Defaults, presence, and domain resolution + +Assigned across schema, decoding, resolution, validation, and consumer examples: + +- Production: `NormalizeConfig.UnmarshalYAML`, `outputPathWasSet`, + `applyPipelineDefaults` and its component default helpers, `Resolve`, + `ResolveLoadedPipelineCampaign`, `mergeCampaignSession`, `selectStableInput`, and + application-supplied byte loading in `internal/app/config_loader.go`. +- Cases: `TestNormalizeLoadAndValidate`, + `TestRepresentativeLoadDefaultsAndValidation`, + `TestMarshalEffectivePipelineRendersStablePublicConfiguration`, + `TestPipelineCampaignRegistryStrictDecode`, + `TestCampaignSessionMergeFillsStableInputs`, + `TestCampaignSessionMergeSessionOverridesStableInputs`, + `TestLoadWithSessionOptionsCarriesExplicitProfilePresence`, and the maintained + extraction-example coverage in `TestMaintainedExtractionExamplesPreservePublishedContracts`. +- Preserve: fresh defaults, explicit-presence-sensitive domain decisions, strict + nested types, stable input selection, application-supplied labeled bytes, and + validation after resolution. +- Adapt: presence comes from metadata rather than custom YAML hooks or pointer/zero + guesses; explicit empty and null values are retained; defaults are cloned and + application-owned; every domain mutation is recorded. Campaign/session fallback, + search paths, fetching, storage, and concrete default values remain in Narratio. + +### Secrets bootstrap + +Assigned to the explicit bootstrap operation: + +- Production: `loadSecretsFromConfigWithDependencies`, `validateSecretDirectory`, + `validateSecretFile`, `readAPIKeyFile`, and + `internal/fileops/read_bounded.go` function `ReadFileBounded`. +- Cases: `TestLoadSecretsFromConfigLoadsValidFiles`, + `TestLoadSecretsFromConfigPreservesExistingEnv`, + `TestLoadSecretsFromConfigRelativeDirUsesCWD`, + `TestLoadSecretsFromConfigMissingDirFails`, + `TestLoadSecretsFromConfigUnreadableValidEntryFails`, + `TestLoadSecretsFromConfigRejectsUnsafeModes`, + `TestLoadSecretsFromConfigRejectsNonRegularAndOversizedEntries`, and + `TestLoadSecretsFromConfigRejectsSymlinkAndAncestorReplacement`. +- Preserve: bounded reads, valid environment names, existing variables (including + empty values) winning, regular-file checks, symlink rejection, and failure cases. +- Adapt: use ConfigKit's deterministic report/preflight/apply state machine and + fixed budgets. Logging, configuration-driven implicit invocation, private-mode + conventions, and application API-key plumbing remain in Narratio. + +## WeatherReporter evidence + +### Secrets bootstrap + +Assigned to the explicit bootstrap operation: + +- Production: `loadSecrets`, `applySecrets`, `restoreEnvironment`, `secretValue`, + and `environmentValue` in `internal/config/secrets.go`. +- Cases: `TestLoadSecretsDisabledLeavesEnvironmentUnchanged`, + `TestLoadSecretsOverwritesExistingEnvironment`, + `TestLoadSecretsTrimsOneTrailingLineEnding`, + `TestLoadSecretsRejectsInvalidDirectoryEntries`, + `TestLoadSecretsRejectsMissingDirectory`, + `TestLoadFileSecretDirectoryFailureLeavesEnvironmentUnchanged`, + `TestLoadFileValidationFailureLeavesSecretEnvironmentUnset`, and + `TestApplySecretsRollsBackOnEnvironmentFailure`. +- Preserve: separate read/preflight and apply mechanisms, one-newline handling, + invalid-name/type/read coverage, no writes after preflight failure, and controlled + environment-write failure coverage. +- Adapt: existing variables—including empty ones—are skipped, never overwritten; + application failures produce an accurate partial report and no rollback. Skip + entries are not read. Bootstrap is explicitly invoked and remains independent of + YAML loading and semantic validation. + +### Defaults, explicit presence, and module options + +Assigned to consumer-shaped examples and migration checks: + +- Production: `Load`, `mergeFile`, `normalizeReportModules`, + `traverseReportModules`, `normalizeModuleOptions`, and `decodeKnownOptions`. +- Cases: `TestDefaults`, `TestOutputDirectoryLoading`, + `TestOutputDirectoryValidationIsConsistentForLoadedAndConstructedConfigs`, + `TestLoadMinimalExampleConfig`, + `TestReportDistributorPathTemplatesSetTracksExplicitEmptyList`, + `TestValidateReportModuleKeysWithoutMutatingOptions`, + `TestReportModuleOverridesNormalizesConstructedOptionsWithoutMutatingConfig`, + `TestReportModuleOverridesCanonicalizesTypedPointerOptions`, + `TestReportDistributorPathOverridesConsistentForLoadedAndConstructedConfig`, + `TestReportModuleValidationConsistentForLoadedAndConstructedConfig`, + `TestConstructedReportOverridesUseExportedFields`, and + `TestConstructedExplicitEmptyReportOverridesAreRejected`. +- Preserve: defaults-only use, consistent loaded/constructed outcomes, explicit + empty-list domain rejection, typed module-specific options, normalization without + mutating caller input, and unknown-field rejection. +- Adapt: ConfigKit permits empty lists structurally and exposes their presence to + application validation. Object bindings replace shorthand, explicitly set flags + become CLI override records, and general environment overlays retire. Report + semantics, registries, rendering, and module option validation remain application + responsibilities. + +## Application-only material + +Do not extract application commands, filesystem discovery, logging, runtime +initialization, remote clients, LLM/provider setup, audio/transcript fixtures, +configuration digests, report rendering, campaign/session algorithms, or consumer +resource validation into ConfigKit. Later consumer examples may use small synthetic +types and fixtures to prove that these responsibilities remain straightforward. diff --git a/docs/internal/overview.md b/docs/internal/overview.md index cbe4646..09c27a9 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -1,8 +1,16 @@ # Internal Component Overview -ConfigKit has no implemented Go packages or components yet. This document will -inventory components and link to their current contracts and focused internal -documentation as they are introduced. +ConfigKit currently contains the root `configkit` package, which establishes the +module and package documentation boundary. It intentionally exposes no loading API +or implemented configuration behavior yet. + +The source-extraction inventory records the application foundations assigned to +future implementation work: + +- [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 diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 36db406..7646660 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -2,7 +2,8 @@ ## Status and ownership -Status: ready for implementation; all stages are pending. +Status: implementation in progress; Stage 1 is complete and later stages are +pending. 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. @@ -282,7 +283,25 @@ rendering must not reveal hidden value histories. ## Stage 1 — Establish the module and extraction baseline -Status: pending. +Status: complete. + +Completion evidence (2026-09-06): + +- Added module `gitea.maximumdirect.net/eric/ConfigKit` at Go 1.25.0 and the + documented root `configkit` package, with no loader API or runtime dependency. +- Added the [source extraction inventory](../internal/extraction.md), recording the + clean Narratio revision `b68435128be1e24b94fc7ec259d6e9093669fd99` and + WeatherReporter revision `5d306a202471e10fe98923a1df27d0b0fce5c666`, assigned + symbols/cases, adaptations, and application-only behavior. No sibling checkout + is a build dependency and no fixture was needed at this boundary. +- Updated the [development baseline](../development.md), [component + inventory](../internal/overview.md), and repository status. The parser remains + planned at `go.yaml.in/yaml/v4 v4.0.0-rc.6`; its module requirement remains + deferred until the real adapter in Stage 3. +- Verified `go test ./...`, `go vet ./...`, `go build ./...`, `git diff --check`, + changed local links, and the introduced file set with Go 1.26.7 on linux/amd64. + 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. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..93f67bc --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module gitea.maximumdirect.net/eric/ConfigKit + +go 1.25.0