Clarify implementation discipline and provenance feature scope

This commit is contained in:
2026-09-12 13:05:00 +00:00
parent 381430a24b
commit 818d36f836
3 changed files with 108 additions and 49 deletions

View File

@@ -1,2 +1,35 @@
Please review `docs/development.md` for initial orientation in this repository Please review `docs/development.md` for initial orientation in this repository
and follow its task-specific reading guide. and follow its task-specific reading guide.
## Implementation Discipline
Simplify the mechanism, not the user's choices.
**Keep implementation machinery proportionate.** Use straightforward,
idiomatic code and introduce only the machinery needed to support the requested
behavior and flexibility. Optimize for conceptual simplicity and
maintainability, not for the fewest lines, fewest options, or narrowest product
surface.
**Do not invent restrictions.** Do not reject, prohibit, constrain, cap,
harden, or otherwise narrow behavior unless required by the user, an explicit
repository contract, or an unavoidable correctness constraint. Preserve
operator and caller choice where policy has not been established. If an
additional restriction appears advisable, present it as a decision rather than
silently implementing it.
A correctness constraint must follow from the requested behavior or an
established invariant, not from the convenience of the chosen implementation.
Explain the specific failure it prevents and why a less restrictive
implementation cannot satisfy the contract.
**An implementation detail is not repository policy.** Tests and documentation
must not elevate incidental behavior into a durable guarantee or restriction
unless that behavior was expressly selected as part of the contract. Existing
explicit contracts remain authoritative; changing or weakening one requires a
deliberate decision rather than being inferred from this principle.
Agent-authored plans, tests, documentation, and prior implementations are not
evidence that an additional restriction was deliberately approved. Identify the
authorizing requirement or decision; when that authority is unclear, surface
the ambiguity rather than treating repetition as approval.

View File

@@ -42,36 +42,42 @@ func (r *Resolution) InputInfo(path Path) (FieldInfo, bool)
func (r *Resolution) Source(id string) (SourceInfo, bool) func (r *Resolution) Source(id string) (SourceInfo, bool)
``` ```
Use a private, immutable entry-state view, not live final metadata. Store only The required behavior is a stable entry-state view and detached public return
effective field records, effective path shapes, and a source-ID index; do not build records, not a particular internal representation. The recommended implementation
or expose an additional historical view. Reuse `Metadata.Lookup` semantics by is a private `Metadata` value containing effective fields and path shapes, together
representing the field/path part as a private `Metadata` value with only those with a source-ID index. Reuse `Metadata.Lookup` semantics. A historical view is not
indexes populated. Never return that `Metadata` value publicly. needed for this feature, and exposing one is outside this sprint's scope.
Build the view after `metadataFromDecoded` and `applyOverlayMetadata` in Build the view after `metadataFromDecoded` and `applyOverlayMetadata` in
`resolveLoadInput`, immediately before `runResolution`, only when a resolver exists. `resolveLoadInput`, immediately before `runResolution`, only when a resolver exists.
Its path shapes come from `decoded.final`, not the raw document or mutable Go Its path shapes come from `decoded.final`, not the raw document or mutable Go
configuration. Clone field records and their nested origins into a separate map; configuration. Separate copies of field/source records are one straightforward way
do not shallow-copy the mutable final metadata map. Build a map keyed by ID from to isolate the view; immutable sharing or ownership transfer is equally acceptable
`assembledInput.sources`, cloning `SourceInfo` records with existing helpers. when it preserves query stability and detached returns. Source records come from
`assembledInput.sources`. Avoid aliases that observable consumer operations or
subsequent metadata updates could mutate while the view remains usable.
Missing or duplicate internally generated IDs are implementation-invariant failures Missing or duplicate internally generated IDs are implementation-invariant failures
to fix, not new consumer-facing diagnostic categories. to fix, not new consumer-facing diagnostic categories.
Pass the private view as an explicit argument to `runResolution` and retain it in Prefer passing the private view explicitly to `runResolution` and retaining it in
`resolutionState`. Update all private callers/tests deliberately: construct their `resolutionState`. Update all private callers/tests deliberately: construct their
entry view from their decoded fixtures and supplied sources where they test these entry view from their decoded fixtures and supplied sources where they test these
queries. Do not add optional/variadic arguments that silently omit provenance in queries. Every production resolution callback must receive complete provenance.
production. Private names are discretionary, but ownership and timing are not. Private signatures and representation may change when an idiomatic alternative
better serves that requirement; record the reasoning in the stage handoff.
Queries first check callback activity through the existing context guard. Only Queries first check callback activity through the existing context guard. Only
then may invalid paths or unknown IDs return misses. `InputInfo` delegates to the then may invalid paths or unknown IDs return misses. `InputInfo` delegates to the
entry metadata lookup; `Source` clones the matched source on return. Preserve entry metadata lookup; `Source` clones the matched source on return. Preserve
existing `IsExplicit`, diagnostics, resolution recording, and secret timing. existing `IsExplicit`, diagnostics, resolution recording, and secret timing.
Do not clone input trees, re-project configuration, read files, resolve symlinks, Queries must not reload input, read files, resolve symlinks, access credentials,
or access credentials during a query. Effective indexing is O(number of entry or re-project mutable configuration instead of reading entry-state information.
paths), source indexing is O(number of sources), and each lookup must avoid a full Prefer reusing existing indexes and avoiding unnecessary whole-tree copies.
tree/source scan. Returned-copy cost is proportional to the returned record. Per-load source indexing is a recommendation, not a complexity guarantee: a simple
scan may be appropriate for the existing bounded source collection. Assess costs
in context, including path lengths and nested record copies; this feature adds no
performance guarantees, resource caps, or benchmark gates.
## Stage 1 — Factor reusable effective-path indexing ## Stage 1 — Factor reusable effective-path indexing
@@ -79,20 +85,23 @@ Status: not started. Dependencies: none.
Scope: `metadata.go`, `load_metadata.go`, and their focused test owners. Scope: `metadata.go`, `load_metadata.go`, and their focused test owners.
1. Extract the effective-path indexing portion of `finalizeMetadataPaths` into one 1. Prepare reusable effective-path lookup for the entry view. The recommended
private helper using existing document traversal and detached path construction. approach extracts indexing from `finalizeMetadataPaths`; an equivalent design
Keep historical indexing and result publication behavior unchanged. may reuse existing traversal directly. Keep historical indexing and result
2. Make result finalization use the extracted helper. Add the private entry-view publication behavior unchanged, and preserve one set of semantic-path rules.
constructor described above, accepting the pre-resolution metadata, decoded 2. Add the private entry-view construction described above using pre-resolution
final tree, and acquired source records. Do not expose public methods yet. metadata, the decoded final tree, and acquired source records. Share extracted
3. Ensure the constructor copies field records and source records without copying machinery with result finalization where useful. Do not expose public methods yet.
history or configuration values. Reuse `cloneFieldInfo`, `cloneSourceInfo`, and 3. Establish and document internal ownership sufficient for stable queries and
existing shape matching instead of writing another path parser or numeric matcher. detached returns. Reuse `cloneFieldInfo` and `cloneSourceInfo` where copying is
needed; do not require eager copies or duplicate history solely to match this
plan's recommended representation.
4. Add focused coverage proving the private view recognizes defaulted fields, 4. Add focused coverage proving the private view recognizes defaulted fields,
missing descendants, root, escaped keys, explicit key/index mismatches, and missing descendants, root, escaped keys, explicit key/index mismatches, and
contextual canonical sequence indices. Prove later mutation of the original contextual canonical sequence indices. Test stability across actual lifecycle
metadata and source records cannot alter the view. Reuse existing shape tests operations and mutation of returned records, not arbitrary mutation of backing
for exhaustive syntax cases rather than duplicating them. data that the implementation owns as immutable. Reuse existing shape tests for
exhaustive syntax cases rather than duplicating them.
Acceptance: all existing final metadata/history behavior is unchanged; a complete Acceptance: all existing final metadata/history behavior is unchanged; a complete
entry view can be constructed before final publication without a historical index. entry view can be constructed before final publication without a historical index.
@@ -185,11 +194,13 @@ explanation/secret integration tests, and consumer guidance.
default-relative paths based on the canonical main source; file-authored paths default-relative paths based on the canonical main source; file-authored paths
based on the scalar's declaring source. Use the existing primary-source identity based on the scalar's declaring source. Use the existing primary-source identity
convention for main-source lookup, not a guess about contributor ordering. convention for main-source lookup, not a guess about contributor ordering.
3. For this file-rooted example, require one unambiguous canonical declaring file 3. Demonstrate file-relative normalization with fixtures that have an unambiguous
for file-relative values. Report a safe application resolution error if that declaring file. If the example handles absent or ambiguous file provenance,
prerequisite is absent or ambiguous. Do not silently use a diagnostic label or make that behavior an explicit example policy, not a correctness requirement
working directory. Non-file-root fallback remains an explicitly separate or prescribed Notarius policy. Rejection, a caller-supplied fallback directory,
application policy, not a new library option. retaining a relative value, or warning are application choices. The example's
selected behavior must be documented and tested; ConfigKit must continue to
expose the distinction rather than fabricate a file from a diagnostic label.
4. Record every changed path through `Normalize` or `Record`, including valid 4. Record every changed path through `Normalize` or `Record`, including valid
dependencies where derived values depend on other configuration paths. Prove dependencies where derived values depend on other configuration paths. Prove
runtime values, effective YAML, and explanation agree; retain the original runtime values, effective YAML, and explanation agree; retain the original
@@ -222,9 +233,10 @@ and proportionate fixes for remaining acceptance failures. No feature expansion.
implementation. Record the mapping in this stage's completion entry. Passing implementation. Record the mapping in this stage's completion entry. Passing
broad suites alone is not evidence that a missing scenario was exercised. broad suites alone is not evidence that a missing scenario was exercised.
2. Inspect every new query path for environment/filesystem access, raw values, 2. Inspect every new query path for environment/filesystem access, raw values,
mutable aliases, accidental callback-lifetime extension, and per-query whole-tree caller-mutable aliases, and accidental callback-lifetime extension. Review
work. Confirm no history was duplicated solely for these queries and loads allocation and traversal costs for proportionality without turning the chosen
without a resolver avoid constructing an unused entry snapshot. mechanism into a public guarantee or adding unsupported performance gates.
Avoid unnecessary history duplication and unused work in no-resolver loads.
3. Review public signatures and current configuration behavior against the previous 3. Review public signatures and current configuration behavior against the previous
release. Confirm the capability is additive and no parser, path, composition, release. Confirm the capability is additive and no parser, path, composition,
credential, or existing callback semantics changed unintentionally. credential, or existing callback semantics changed unintentionally.
@@ -260,8 +272,10 @@ Validation: `./scripts/check.sh`, `go test -race ./...`, and the full checker ab
## Open Questions ## Open Questions
None blocking implementation. The API, snapshot boundary, missing-value semantics, None blocking implementation. The API, snapshot boundary, missing-value semantics,
source identity handling, ownership, and example fallback policy are specified by source identity handling, and ownership are specified by the roadmap and decisions
the roadmap and decisions above. Release version and publication timing are later above. Example fallback behavior is illustrative application policy, not a missing
library contract; record any selected example behavior without prescribing it to
consumers. Release version and publication timing are later
maintainer decisions, not unresolved implementation choices. If new evidence maintainer decisions, not unresolved implementation choices. If new evidence
contradicts a target contract, document the conflict, a recommended correction and contradicts a target contract, document the conflict, a recommended correction and
its rationale, and at least one viable alternative before proceeding past it. its rationale, and at least one viable alternative before proceeding past it.

View File

@@ -107,7 +107,9 @@ source still supplies no directory, and the application must choose its fallback
Multiple locations do not imply one declaring file. Consumers needing a single Multiple locations do not imply one declaring file. Consumers needing a single
file must inspect the exact value's origin and source records and handle ambiguity file must inspect the exact value's origin and source records and handle ambiguity
explicitly. No new `DeclaringFile` shortcut should silently discard contributors. according to application policy. ConfigKit does not require rejection: an
application may choose an explicit fallback, retain a relative value, warn, or
report an error. No new `DeclaringFile` shortcut should silently discard contributors.
### Lifetime and detachment ### Lifetime and detachment
@@ -150,18 +152,20 @@ overlay history before calling `runResolution`. Pass a read-only entry-state
provenance view and the load's acquired source records into the private resolution provenance view and the load's acquired source records into the private resolution
state. No public parser types or new external dependencies are needed. state. No public parser types or new external dependencies are needed.
The view must have complete effective semantic-path indexing when the callback The view must support complete effective semantic-path lookup when the callback
starts. Current result metadata indexes are finalized later; exposing an unfinished starts. Current result metadata indexes are finalized later; exposing an unfinished
`Metadata` value would make legitimate lookups fail. Reuse or factor existing `Metadata` value would make legitimate lookups fail. Reuse or factor existing
effective-path traversal and shape matching so entry queries and final queries effective-path traversal and shape matching so entry queries and final queries
cannot acquire different path semantics. A full historical index or public cannot acquire different path semantics. A full historical index or public
`Metadata.History` interface during resolution is not required by this feature. `Metadata.History` interface during resolution is not required by this feature.
Keep the view independent of metadata updates performed after resolution. Keep queries stable across consumer normalization and return detached records.
Implementations may share immutable backing data privately while returning detached Private copying, immutable sharing, or ownership transfer may satisfy that contract;
records; do not copy an entire configuration tree per query. Source lookup should no particular backing representation or eager-copy strategy is required. Prefer
use a per-load index or equivalent bounded existing mechanism, rather than requiring existing traversal/indexing machinery and proportionate allocation. A per-load
each consumer to rebuild source bookkeeping. source index is a recommended mechanism, not a public complexity guarantee or a
prohibition on scanning the bounded existing source collection. Consumers should
not need to rebuild source bookkeeping themselves.
The source and input views remain bounded by existing load limits. They contain The source and input views remain bounded by existing load limits. They contain
provenance records, not configuration values or resolved credentials. Do not read provenance records, not configuration values or resolved credentials. Do not read
@@ -207,14 +211,22 @@ behavioral owners rather than duplicate every mechanism at every layer. Acceptan
does not require a live Notarius checkout, external credentials, or target-file does not require a live Notarius checkout, external credentials, or target-file
existence checks. existence checks.
## Explicit exclusions ## Scope and existing boundaries
Do not add automatic path-string recognition, filesystem path normalization, Application responsibilities remain application responsibilities: interpreting
existence checks, path confinement, default/CLI base selection, source discovery, path-valued strings, normalizing filesystem paths, choosing default/CLI bases,
new import/profile composition rules, historical value access during resolution, and deciding whether to check existence, impose confinement, or use fallbacks.
automatic move tracking, post-load mutability, or a general provenance service. This feature neither performs those operations nor prohibits consumers from doing so.
Actual Notarius integration remains downstream work. Actual Notarius integration remains downstream work.
Existing contracts, including import/profile composition and frozen post-load
inspection, remain unchanged. Their authority comes from the current contracts,
not from this roadmap's exclusions.
Source discovery, historical value access during resolution, automatic move
tracking, and a general provenance service are not included in this feature.
That scope choice is not a repository-wide prohibition on future proposals.
## Compatibility and canonical ownership ## Compatibility and canonical ownership
This is an additive public capability; existing callbacks, loading order, and This is an additive public capability; existing callbacks, loading order, and