Retire completed roadmaps before the next release
This commit is contained in:
@@ -43,7 +43,7 @@ public behavior.
|
||||
| Shared source-version checks | [Configuration contract](config.md#shared-source-version-checks), [ADR 0013](adr/0013-shared-source-version-checks.md), and the version/source-version tests below |
|
||||
| Documentation changes | The owning document |
|
||||
| Licensing, dependencies, attribution, or release-document changes | [Project grant](../COPYRIGHT) and [attribution](oss/attribution.md); release changes also follow the release procedure |
|
||||
| Architecture decisions or future work | [Future features](roadmap/future.md), [remediation roadmap](roadmap/roadmap.md), and relevant ADRs listed below |
|
||||
| Architecture decisions or future work | [Future features](roadmap/future.md) and relevant ADRs listed below |
|
||||
| Code and test changes | The owning contract and tests from the map below |
|
||||
| Examples or copyable assets | The owning implemented contract and [consumer adoption guide](consumers/README.md) |
|
||||
| Release preparation | [Release procedure](release.md) |
|
||||
@@ -199,8 +199,25 @@ git show 34cbc0d:docs/roadmap/remediation.md
|
||||
```
|
||||
|
||||
Potential enhancements are tracked in [future features](roadmap/future.md).
|
||||
The completed audit remediation's scope is recorded in the
|
||||
[remediation roadmap](roadmap/roadmap.md). The consolidated audit, including
|
||||
The completed audit-remediation, internal-boundary simplification, shared-history,
|
||||
and public API cleanup roadmaps, reviews, and resolved findings are preserved at
|
||||
`68400ff` under `docs/roadmap/`. For example:
|
||||
|
||||
```sh
|
||||
git show 68400ff:docs/roadmap/api.md
|
||||
git show 68400ff:docs/roadmap/remediation.md
|
||||
```
|
||||
|
||||
Their earlier completed implementation plans are preserved at
|
||||
`bb5540b:docs/roadmap/implementation.md` (audit remediation),
|
||||
`f6d54a0:docs/roadmap/implementation.md` (internal-boundary simplification), and
|
||||
`07e4ae5:docs/roadmap/implementation.md` (shared history). The plan at
|
||||
`68400ff:docs/roadmap/implementation.md` records the public API cleanup.
|
||||
Current behavior and migration information belong to the
|
||||
[configuration contract](config.md), public declaration comments, and
|
||||
[consumer guide](consumers/README.md#pre-v1-public-api-cleanup).
|
||||
|
||||
The consolidated audit, including
|
||||
findings, evidence, and settled scope decisions, is preserved at
|
||||
`453da68:docs/roadmap/audit.md`; the original nine reports are preserved at
|
||||
`ecd5d5d` under `docs/roadmap/`. Retrieve the consolidated record with:
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
# Pre-v1 Public API Cleanup Roadmap
|
||||
|
||||
Status: implemented. The accepted API changes and integrated validation are
|
||||
recorded in the [implementation plan](implementation.md).
|
||||
Planning baseline: `7548fa1` (accepted decisions, with the v0.10.2 implementation
|
||||
and subsequent interface/history remediation already present).
|
||||
|
||||
This roadmap owns the targeted end state, required changes, and completion
|
||||
criteria. The [implementation plan](implementation.md) owns concrete edits,
|
||||
sequential stages, validation commands, and progress tracking. The
|
||||
[preliminary review](review.md) retains the API catalog and original proposals;
|
||||
the [additional review](audit.md) retains
|
||||
its evidence and alternatives. Proposal IDs below provide traceability.
|
||||
|
||||
## Purpose And Scope
|
||||
|
||||
Make the public API clearer before v1.0.0 through the accepted renames, narrower
|
||||
recording methods, redundant-state removal, and direct source lookups. Preserve
|
||||
existing configuration behavior except for the selected public replacements,
|
||||
removals, and observable string changes. The root package remains the supported
|
||||
facade; private engine structure can evolve within that boundary.
|
||||
|
||||
This is a breaking pre-v1 cleanup, not a compatibility-shim rollout. The renamed
|
||||
or replaced public declarations give way to their selected forms. Existing Go
|
||||
declaration comments and the [configuration contract](../config.md) continue to
|
||||
own behavior that this roadmap does not change. No redesign of loading,
|
||||
composition, history ownership, or YAML syntax is selected.
|
||||
|
||||
## Current Baseline
|
||||
|
||||
- [lifecycle.go](../../lifecycle.go), [records.go](../../records.go),
|
||||
[discovery.go](../../discovery.go), and [secrets.go](../../secrets.go) expose
|
||||
the old declarations listed below. There are corresponding engine declarations
|
||||
and facade conversions, including [conversion.go](../../conversion.go).
|
||||
- `Resolution.Record` accepts the inspection `ChangeKind` type, then rejects
|
||||
kinds other than derived-default and normalization during loading. The generic
|
||||
assignment helpers already select their own supported intent.
|
||||
- `ImportSelection` represents only empty selections, but still carries a
|
||||
single-valued outcome. Source records expose version and destination evidence
|
||||
through names that do not fully describe that evidence.
|
||||
- `Resolution.Source(id)` already performs passive, detached lookup during a
|
||||
callback. `Result` and `LoadError` expose ordered `Sources()` lists but no
|
||||
direct lookup. Failure records contain only the evidence available at failure.
|
||||
- The shared history implementation and its admission boundary are already in
|
||||
place. Provenance still uses `"base"`, and retained-history failures still use
|
||||
`"explain.limit_exceeded"`.
|
||||
- Current production-reference checks find only declarations for
|
||||
`CodeOptionsUnavailable`, and the kind guard in `resolutionState.addRecord`
|
||||
produces `CodeResolveInvalidKind`. Their removal requires the checks described
|
||||
below, rather than inventing a new supported use for either code.
|
||||
|
||||
## Targeted Public API
|
||||
|
||||
The following table is the complete accepted change set. Unless stated otherwise,
|
||||
renames retain the existing signature/type and behavior. Internal names are not
|
||||
part of this public replacement list.
|
||||
|
||||
| Review item | Decision |
|
||||
| --- | --- |
|
||||
| D1 | Rename `Resolution.InputInfo` to `EntryInfo`, describing the fixed resolution-entry metadata view, including retained defaults and CLI assignments. Preserve its return type and lookup behavior. |
|
||||
| D2 | Rename `Definition.Secret` to `Sensitive`. Preserve classification behavior, the `configkit:"secret"` tag, and typed `Secret` references. |
|
||||
| D3 | Rename `SourceVersionModeDefault` to `SourceVersionModeMainOnly`, `SourceVersionCheck` to `SourceVersionEvidence`, and `SourceInfo.VersionCheck` to `VersionEvidence`. Retain `SourceVersionModeIfPresent` and `SourceVersionModeRequired`. |
|
||||
| D4 | Rename `ImportSelection` to `EmptyImportSelection` and `SourceInfo.ImportSelections` to `EmptyImportSelections`. Retain path, location, and selector; remove `Outcome`, `ImportSelectionOutcome`, and `ImportSelectionNone`. |
|
||||
| D5 | Rename `SourceInfo.DestinationUnresolved` to `DestinationIsFallback`, preserving its existing meaning and destination coordinates. |
|
||||
| D6 (including N4) | Replace `Resolution.Record` with the two intent-specific methods below and remove `CodeResolveInvalidKind` once its public trigger is eliminated. Retain `ChangeKind` and its inspection constants. |
|
||||
| D7 | Rename `LoadSecretsDir` to `LoadSecretsIntoEnvironment`, making process-environment mutation explicit. Preserve its signature apart from the name, report-plus-error behavior, and existing bootstrap semantics. |
|
||||
| D8 | Remove `CodeOptionsUnavailable` after confirming there is no intentional supported role. Do not introduce a failure merely to give the code a producer; a concrete reason to retain it should be brought back for discussion. |
|
||||
| A1 (including N5) | Add `Result.Source(id)` and `LoadError.Source(id)` for direct lookup of source evidence on successful and failed loads, alongside their existing `Sources()` enumeration. Keep source evidence distinct from passive resource access through `SourceContext(id)`. |
|
||||
| N1 | Rename `Paths(paths ...string) Search` to `SearchPaths(paths ...string) Search`, replacing the old name outright. Preserve literal file candidates, ordering, deferred acquisition, and selection/failure behavior. Leave semantic `Path` APIs and `Searches` unchanged. |
|
||||
| N2 | Replace `LayerBase = "base"` with `LayerMain = "main"`, without a compatibility alias. Update Go references and affected string comparisons, serialization, and rendered labels. Preserve the existing main-tier category, imported contributions' owning tiers, precedence, and acquisition order. |
|
||||
| N3 | Replace `CodeExplainLimitExceeded = "explain.limit_exceeded"` with `CodeHistoryLimitExceeded = "history.limit_exceeded"`, without a compatibility alias. Update Go references and affected diagnostic-code consumers. Preserve the existing quota, retained-node accounting, failure conditions, diagnostic locations, and admission timing before effective secret lookup and application validation. |
|
||||
| N6 | Rename `ImportDefaults.Follow` to `FollowSymlinks` and `ImportDefaults.Hidden` to `IncludeHidden`, replacing the old fields outright. Preserve `*bool` types, nil defaulting, explicit true/false, declaration overrides, traversal behavior, and search scope. Keep YAML keys `follow` and `hidden`, and Go fields `Required`, `Recursive`, and `Pattern`, unchanged. |
|
||||
|
||||
### Recording Methods (D6)
|
||||
|
||||
The selected signatures are:
|
||||
|
||||
```go
|
||||
func (r *Resolution) RecordDerivedDefault(path Path, reason string, dependencies ...Path)
|
||||
func (r *Resolution) RecordNormalization(path Path, reason string, dependencies ...Path)
|
||||
```
|
||||
|
||||
Both record intent for work already performed by application code. They do not
|
||||
assign values; `RecordDerivedDefault` does not check absence or suppress work on
|
||||
explicit input. Keep `Default` and `Normalize` as the assignment-and-recording
|
||||
helpers. Preserve path/reason/dependency validation, container coverage,
|
||||
coalescing, net-change auditing, and callback lifetime. Replace the old `Record`
|
||||
method outright rather than retain parallel public recording interfaces.
|
||||
|
||||
Include N4's diagnostic cleanup in this change: confirm that no supported public
|
||||
input can still produce `resolve.invalid_kind`, then remove `CodeResolveInvalidKind`
|
||||
without a replacement or compatibility alias. Preserve other recording diagnostics.
|
||||
Internal defensive checks remain an implementation choice. If another legitimate
|
||||
public trigger is found, bring it back for discussion rather than silently
|
||||
reclassifying the failure.
|
||||
|
||||
### Version Policy And Evidence (D3)
|
||||
|
||||
`MainOnly` remains the zero mode and does not enable checking without a configured
|
||||
version rule. The broader modes retain their requirement for a usable rule.
|
||||
Document the modes together, preserving these distinctions:
|
||||
|
||||
- `MainOnly` retains the existing main-version check at its effective path.
|
||||
Broader modes inspect each participating document in source-local coordinates
|
||||
before placement and composition.
|
||||
- `IfPresent` passes an absent main declaration to the application checker, while
|
||||
absent non-main declarations skip the checker. `Required` rejects missing
|
||||
declarations in participating documents. Existing `NoSource` behavior remains.
|
||||
- Version evidence describes observed declarations or absence, not checker
|
||||
invocation or acceptance. Preserve nil-versus-observed-absence meaning,
|
||||
explicit null, locations, consumption, and redaction. No acceptance flag is added.
|
||||
|
||||
### Direct Source Lookup (A1)
|
||||
|
||||
```go
|
||||
func (r *Result[T]) Source(id string) (SourceInfo, bool)
|
||||
func (e *LoadError) Source(id string) (SourceInfo, bool)
|
||||
```
|
||||
|
||||
Look up an acquired source by its load-local ID, returning the same information
|
||||
represented in `Sources()` as a detached record. Empty or unknown IDs return
|
||||
false. The query performs no source acquisition, filesystem access, or credential
|
||||
lookup. Reuse existing source lookup and conversion machinery where practical;
|
||||
no public registry, indexing strategy, or constant-time guarantee is required.
|
||||
|
||||
The failed-load lookup returns records from `LoadError.Sources()`'s partial
|
||||
inventory and returns false for nil or zero-valued errors as well. Preserve
|
||||
existing failed-load redaction and the evidence available at failure, including
|
||||
incomplete placement information. Lookup neither completes acquisition nor
|
||||
promises a record for every attempted source. This incorporates N5 into A1.
|
||||
|
||||
## Work Required From The Baseline
|
||||
|
||||
### Public Declarations And Facade Conversions
|
||||
|
||||
Update the public declarations, comments, wrappers, and conversions as a coherent
|
||||
surface. Useful existing owners are:
|
||||
|
||||
| Area | Baseline owners and required work |
|
||||
| --- | --- |
|
||||
| Entry metadata, sensitivity, version mode, and import defaults | [lifecycle.go](../../lifecycle.go), [layered.go](../../layered.go), and [conversion.go](../../conversion.go): update both ordinary and layered loading paths, callback wrappers, and definition/default conversions. |
|
||||
| Source evidence | [records.go](../../records.go) and [conversion.go](../../conversion.go): rename records/fields and remove the empty-selection outcome. Cover source records returned through results, callbacks, and load errors. |
|
||||
| Recording intents | [lifecycle.go](../../lifecycle.go) and [engine resolution](../../internal/engine/resolution.go): provide the two methods, route them to the existing recording/auditing machinery, and remove the public kind-selecting method. |
|
||||
| Discovery and bootstrap | [discovery.go](../../discovery.go) and [secrets.go](../../secrets.go): replace constructor/function names and migrate their callers without changing acquisition or environment mutation behavior. |
|
||||
| Provenance and diagnostic values | [records.go](../../records.go), [engine records](../../internal/engine/records.go), producers, conversions, and renderers: apply the selected labels and codes consistently. |
|
||||
| Direct lookup | [lifecycle.go](../../lifecycle.go), [diagnostic.go](../../diagnostic.go), and their engine collaborators: expose the existing retained source evidence through the new result/error methods. |
|
||||
|
||||
Use explicit root/engine conversion as needed; no public aliases or engine types
|
||||
are needed to implement these replacements. Private naming and helper placement
|
||||
belong to implementation planning. Avoid unrelated internal renames merely to
|
||||
make every private identifier match the facade.
|
||||
|
||||
Preserve distinctions that the new names clarify:
|
||||
|
||||
- `EntryInfo` remains a fixed, detached entry-state lookup with its current
|
||||
unknown/invalid/shape-mismatch behavior. `IsExplicit` retains its own existing
|
||||
validation behavior; the rename does not unify those two query contracts.
|
||||
- `Sensitive` remains the classification predicate, separate from typed secret
|
||||
references. Existing tag/predicate/dependency classification and redaction
|
||||
still apply.
|
||||
- `DestinationIsFallback` still describes the nearest resolved enclosing
|
||||
container when the full destination is unavailable. It does not promise an
|
||||
item's exact coordinates or upgrade evidence retained at an earlier stage.
|
||||
- Empty-selection records keep their existing scope, order, and declaration-local
|
||||
coordinates. Removing `Outcome` does not create a complete import ledger.
|
||||
- `FollowSymlinks` and `IncludeHidden` retain pointer defaulting and load-preflight
|
||||
snapshot behavior. Do not mechanically rename YAML `follow` or `hidden` keys.
|
||||
|
||||
### Recording Entry Points And Obsolete Diagnostics
|
||||
|
||||
Implement the two recording methods over the existing resolution lifecycle.
|
||||
Migrate manual-record callers according to the intent they currently supply;
|
||||
keep assignment helper calls as helpers. Tests of container coverage, overlapping
|
||||
records, dependencies, equal-valued intent, and net-change auditing continue to
|
||||
protect the same behavior through the new entry points.
|
||||
|
||||
Complete the N4 check after replacing `Record`: trace supported recording routes,
|
||||
then remove the obsolete exported invalid-kind code if its public trigger is
|
||||
gone. Update tests of the removed input mechanism without weakening unrelated
|
||||
record validation. Do not introduce a different public diagnostic solely to
|
||||
represent an unreachable kind.
|
||||
|
||||
For D8, confirm both producer references and any documented intentional role for
|
||||
`CodeOptionsUnavailable`, then remove the unused declaration and associated
|
||||
active documentation. A concrete supported role discovered during this check
|
||||
should be brought back for discussion. These are verification tasks for accepted
|
||||
removals, not permission to delete other diagnostics that happen to be uncommon.
|
||||
|
||||
### Direct Lookup And Source Evidence
|
||||
|
||||
Implement the result and error methods against each receiver's retained source
|
||||
inventory. Reuse source-copying and facade-conversion helpers where practical so
|
||||
lookup and enumeration agree, including nested locations, version evidence,
|
||||
empty-selection evidence, and detached paths. Follow existing result-query
|
||||
nil/zero conventions; failed-load nil/zero behavior is specified above.
|
||||
|
||||
Keep `Sources()` enumeration and `SourceContext(id)` responsibilities intact.
|
||||
Lookup must not repeat acquisition, finalize failure evidence, or change source
|
||||
IDs. A slice search or a suitable existing index can satisfy the contract; no
|
||||
new lookup complexity promise or shared lazy cache is selected.
|
||||
|
||||
### Observable Strings And Their Producers And Readers
|
||||
|
||||
Replace the main-tier category's `"base"` spelling with `"main"` wherever that
|
||||
category crosses the public boundary or is rendered. Imported contributions keep
|
||||
their owning tier and ordinary source-location attribution. Other uses of the
|
||||
word "base", such as filesystem base directories, are unrelated.
|
||||
|
||||
Change every retained-history-limit diagnostic producer and relevant reader to
|
||||
`"history.limit_exceeded"`, including inheritance and final load admission.
|
||||
Preserve the quota, accounting, and failure timing. This rename does not make
|
||||
history optional or add a new limit control.
|
||||
|
||||
Review Go constant references and literal comparisons/expected output separately:
|
||||
compilation catches old symbols but not stale diagnostic or provenance strings.
|
||||
Other codes and layer values retain their existing meaning and spelling.
|
||||
|
||||
### Consumer Guidance And Migration Information
|
||||
|
||||
Update declaration comments, applicable sections of [config.md](../config.md),
|
||||
the [consumer guide](../consumers/README.md), README examples, and maintained
|
||||
consumer code/fixtures under `examples/`. Use the new recording methods and source
|
||||
lookups in relevant existing examples without expanding unrelated workflows.
|
||||
Update internal documentation only where implemented ownership or terminology
|
||||
changes. Accepted ADR decisions do not need revision for this cleanup.
|
||||
|
||||
Record the old-to-new Go names, removed outcome fields/codes, recording-call
|
||||
replacements, and the two observable string changes as migration information.
|
||||
Downstream applications may need to update literal comparisons and serialized
|
||||
expectations as well as Go references. Version-specific release notes and
|
||||
publication remain part of the normal [release process](../release.md); this
|
||||
roadmap does not select a release version or authorize publication.
|
||||
|
||||
Keep revision-pinned review evidence and historical release records accurate for
|
||||
their original revisions. Old names in those records are not stale active API
|
||||
usage. Do not rewrite history or require external consumer migrations to claim
|
||||
the repository implementation is complete.
|
||||
|
||||
## Validation And Completion
|
||||
|
||||
Follow the [testing policy](../policy/testing.md) and
|
||||
[development guide](../development.md#baseline-validation). Reuse existing
|
||||
behavioral tests for mechanical renames; new tests should protect the changed
|
||||
entry points and added lookups, rather than duplicate implementation details.
|
||||
|
||||
- Check the root API exposes every selected replacement/addition and no obsolete
|
||||
public declarations from the accepted removals. Preserve root-owned type
|
||||
identity and the existing public/dependency boundary checks. Historical
|
||||
references and useful private implementation names do not invalidate this check.
|
||||
- Exercise both recording intents through the new public methods. Preserve
|
||||
helper assignment behavior, validation, recorded origins, and history under
|
||||
the existing resolution tests; update the old invalid-kind case when its input
|
||||
mechanism is removed.
|
||||
- Cover successful and failed source lookup against each receiver's enumeration,
|
||||
missing IDs, applicable nil/zero cases, detachment of nested evidence, and
|
||||
unchanged records after caller mutation. Reuse existing source/version/resource
|
||||
fixtures for redaction, partial failure evidence, and passive access behavior.
|
||||
Do not add source-completeness, performance, or concurrency guarantees.
|
||||
- Retain the existing entry-shape, sensitivity, version-mode, empty-selection,
|
||||
placement, import-default snapshot, discovery, and secrets-bootstrap coverage.
|
||||
In particular, Go field renames must leave YAML declarations and tri-state
|
||||
defaulting behavior intact.
|
||||
- Update relevant provenance and diagnostic assertions for the selected strings.
|
||||
Existing history-budget cases should continue to check rejection before secret
|
||||
lookup and application validation, using the new code and unchanged accounting.
|
||||
- Run the applicable focused checks during development and the everyday check
|
||||
for the integrated code changes. Apply existing race-check guidance if the
|
||||
implementation changes ownership/concurrency behavior. Validate documentation
|
||||
links and maintained examples. No benchmark campaign or additional release
|
||||
gate is introduced.
|
||||
|
||||
Completion means all accepted proposals are implemented, the diagnostic-removal
|
||||
checks are resolved, maintained consumers and current documentation use the new
|
||||
surface, and applicable checks pass with behavior preserved except for the
|
||||
expressly selected changes. Update roadmap/review status with the actual evidence;
|
||||
passing the current baseline suite is not evidence of future implementation.
|
||||
|
||||
No significant open design decision remains. D8's role check and D6/N4's public
|
||||
reachability check are implementation verification tasks; unexpected evidence of
|
||||
a legitimate public use should be discussed before changing that use. Private
|
||||
helper choices and lookup mechanics are selected in the implementation plan.
|
||||
Public path comparison (A2) remains deferred and outside this scope.
|
||||
@@ -1,201 +0,0 @@
|
||||
# Additional Public API Review
|
||||
|
||||
Reviewed revision: `3ebb848eadf6e61275ecec6e35838ad6576cdd3a`.
|
||||
Status: N1–N6 accepted, with N4 incorporated into D6 and N5 into A1.
|
||||
Implementation has not begun.
|
||||
|
||||
## Scope And Assessment
|
||||
|
||||
This review accepts the inventory in [review.md](review.md) and independently
|
||||
assesses the public interface through consumer workflows, declaration comments,
|
||||
the [configuration contract](../config.md), and targeted implementation tracing.
|
||||
It covers loading/discovery, source and resource ownership, paths and collection
|
||||
registration, callbacks, inspection/diffs, secrets, and diagnostics. It does not
|
||||
repeat the symbol inventory or conduct a correctness/performance audit.
|
||||
|
||||
[api.md](api.md) owns the accepted D1–D8, A1, and N1–N6 changes. Those decisions remain
|
||||
settled; public path comparison (A2) remains deferred. The findings here are
|
||||
additional opportunities, including consequences of the accepted cleanup.
|
||||
|
||||
The principal API boundaries remain useful. No broader consolidation of loading
|
||||
options, filesystem roles, callbacks, or the two history projections is warranted
|
||||
by this review. The remaining opportunities concern vocabulary, removal of an
|
||||
obsolete input-error category, and a missing convenience on failed loads.
|
||||
|
||||
| Finding | Recommendation | Compatibility impact if accepted |
|
||||
| --- | --- | --- |
|
||||
| N1: discovery `Paths` (accepted) | Rename to `SearchPaths`; decision recorded in [api.md](api.md). | Go function rename. |
|
||||
| N2: main-tier provenance (accepted) | Rename `LayerBase` to `LayerMain`, with value `"main"`; decision recorded in [api.md](api.md). | Go constant rename and observable string change. |
|
||||
| N3: shared-history quota (accepted) | Rename `CodeExplainLimitExceeded` to `CodeHistoryLimitExceeded`, with value `"history.limit_exceeded"`; decision recorded in [api.md](api.md). | Go constant rename and machine-readable code change. |
|
||||
| N4: recording-kind diagnostic (accepted through D6) | Incorporated into [D6 in api.md](api.md#recording-methods-d6). | Conditional constant removal. |
|
||||
| N5: failed-load source lookup (accepted through A1) | Incorporated into [A1 in api.md](api.md#direct-source-lookup-a1). | Compatible addition. |
|
||||
| N6: import-default field names (accepted) | Rename to `FollowSymlinks` and `IncludeHidden`; decision recorded in [api.md](api.md). | Go field renames; YAML keys unchanged. |
|
||||
|
||||
These accepted design changes are not defect severities or additional release
|
||||
gates. The string-value changes in N2 and N3 are explicitly accepted.
|
||||
|
||||
## N1. Distinguish Discovery Paths From Semantic Paths
|
||||
|
||||
Status: accepted. [api.md](api.md) owns the selected change; the discussion below
|
||||
preserves its rationale and alternatives.
|
||||
|
||||
Evidence: [path.go](../../path.go) defines `Path`, `Keys`, and `ParsePath` for
|
||||
configuration-value coordinates. [discovery.go](../../discovery.go) defines
|
||||
`Paths(paths ...string) Search` for literal host-file candidates. In the same
|
||||
package, the plural of `Path` therefore constructs a different concept rather
|
||||
than a collection of semantic paths. The preliminary catalog recommends retaining
|
||||
the name and explaining the distinction.
|
||||
|
||||
Recommendation: rename the discovery constructor to
|
||||
`SearchPaths(paths ...string) Search`. This aligns it with `SearchDirectory` and
|
||||
makes a call such as `SearchPaths("./app.yml", "/etc/app.yml")` recognizable
|
||||
without inspecting its return type. Keep literal-path interpretation, candidate
|
||||
order, deferred acquisition, and all search behavior unchanged. No rename of
|
||||
`Path`, new path type, or discovery redesign is needed.
|
||||
|
||||
Alternative: retain `Paths`. It is concise inside `SearchConfig` and its comment
|
||||
is accurate, but package completion and standalone calls still mix filesystem
|
||||
and configuration-path vocabulary. `FileCandidates` is another viable name,
|
||||
although it is less consistent with `SearchDirectory`.
|
||||
|
||||
## N2. Use Main Consistently In Provenance
|
||||
|
||||
Status: accepted, including the string-value change. [api.md](api.md) owns the
|
||||
selected change; the discussion below preserves its rationale and alternatives.
|
||||
|
||||
Evidence: `LoadLayered(main, ...)`, `SourceInfo.UnderlayIndex`, the configuration
|
||||
contract, and the accepted `SourceVersionModeMainOnly` name distinguish main input
|
||||
from lower-priority underlays. [records.go](../../records.go) instead exposes
|
||||
`LayerBase = "base"` for the main tier. A consumer presenting provenance must
|
||||
learn that this base is above underlays and is distinct from application defaults.
|
||||
The preliminary catalog treats this as a documentation concern.
|
||||
|
||||
Recommendation: use `LayerMain = "main"` so API calls, provenance records, and
|
||||
rendered layer labels use the same term. Preserve the existing layer category and
|
||||
all precedence rules; imported contributions retain their owning tier. This is
|
||||
a vocabulary change, not a new layer or a change to source acquisition order.
|
||||
|
||||
Changing the literal affects applications that compare, serialize, or display
|
||||
layer strings as well as those referring to the Go constant. If selected, migrate
|
||||
those uses and document the change together before v1.
|
||||
|
||||
Alternative: rename only the Go constant and keep `"base"`. That reduces string
|
||||
compatibility impact but preserves two names for the same concept in application
|
||||
code and rendered evidence. Keeping both the existing symbol and value is also
|
||||
reasonable if the modest clarity gain does not justify migration; the preferred
|
||||
pre-v1 outcome is one consistent term.
|
||||
|
||||
## N3. Name The Retained-History Limit For Its Actual Scope
|
||||
|
||||
Status: accepted, including the diagnostic-code string change. [api.md](api.md)
|
||||
owns the selected change; the discussion below preserves its rationale and alternatives.
|
||||
|
||||
Evidence: [records.go](../../records.go) exposes
|
||||
`CodeExplainLimitExceeded = "explain.limit_exceeded"`. Its production sites include
|
||||
`executeLoadRequest` in [load.go](../../internal/engine/load.go) and
|
||||
`inheritanceHistoryBudgetDiagnostic` in
|
||||
[inheritance_walk.go](../../internal/engine/inheritance_walk.go). It can fail a load
|
||||
without an application calling `Explain`. The completed shared model supplies
|
||||
metadata, explanation, historical membership, and internal attribution readers.
|
||||
|
||||
Recommendation: rename the constant to `CodeHistoryLimitExceeded` and its value
|
||||
to `"history.limit_exceeded"`. This describes the resource being bounded and
|
||||
avoids suggesting that skipping explanation would avoid the load failure.
|
||||
Preserve the quota, retained-node accounting, diagnostic locations, and admission
|
||||
timing. This does not add a limit setting or change which configurations load.
|
||||
|
||||
Alternative: rename the Go constant but retain the existing code string, or keep
|
||||
both names unchanged and clarify the diagnostic documentation. Either preserves
|
||||
more consumer compatibility, but a retained `"explain.limit_exceeded"` remains
|
||||
misleading to applications that work directly with diagnostic codes. A coordinated
|
||||
pre-v1 change is preferable if the new terminology is accepted.
|
||||
|
||||
## N4. Review The Diagnostic Made Obsolete By D6
|
||||
|
||||
Status: accepted and incorporated into [D6](api.md#recording-methods-d6). The
|
||||
discussion below preserves the rationale and alternative.
|
||||
|
||||
Evidence: the production use of `CodeResolveInvalidKind` is the kind guard in
|
||||
`resolutionState.addRecord` in
|
||||
[resolution.go](../../internal/engine/resolution.go). Today, public `Record` can
|
||||
pass arbitrary `ChangeKind` values into it. Accepted D6 replaces that method with
|
||||
two methods that select supported intents; `Default` and `Normalize` also supply
|
||||
fixed supported kinds. This is distinct from D8's already unproduced
|
||||
`CodeOptionsUnavailable`.
|
||||
|
||||
Recommendation: as part of D6 implementation, confirm that no supported public
|
||||
input can produce `resolve.invalid_kind`, then remove its exported constant.
|
||||
Retain the other recording diagnostics and the inspection `ChangeKind` values.
|
||||
Internal defensive checks can remain where useful; their representation does
|
||||
not require an unreachable public configuration-error category.
|
||||
|
||||
Alternative: retain the constant for consistency with previous diagnostics or
|
||||
a concrete future use. That costs little code but leaves an unexplained public
|
||||
error category after its input mechanism has disappeared. Do not add a public
|
||||
trigger simply to justify keeping it. The removal remains conditional on the
|
||||
final D6 implementation, rather than assuming a guard must be deleted now.
|
||||
|
||||
## N5. Offer Direct Source Lookup On Failed Loads
|
||||
|
||||
Status: accepted and incorporated into [A1](api.md#direct-source-lookup-a1). The
|
||||
discussion below preserves the rationale and alternative.
|
||||
|
||||
Evidence: [diagnostic.go](../../diagnostic.go) exposes `LoadError.Diagnostics()`
|
||||
and `LoadError.Sources()`. Diagnostic primary and related locations refer to
|
||||
source IDs. Accepted A1 adds direct lookup on successful results, while
|
||||
`Resolution.Source` already supports it during callbacks. A custom error reporter
|
||||
still has to scan or index the failed load's source slice to follow the same IDs.
|
||||
|
||||
Recommendation: add this companion to A1:
|
||||
|
||||
```go
|
||||
func (e *LoadError) Source(id string) (SourceInfo, bool)
|
||||
```
|
||||
|
||||
It should return a detached record from the same partial inventory as
|
||||
`LoadError.Sources()`, with false for empty/unknown IDs and nil/zero errors.
|
||||
Preserve the existing failed-load redaction and available evidence; a lookup
|
||||
does not complete acquisition or upgrade a partial destination/version record.
|
||||
This is passive lookup, with no filesystem access or new source-completeness
|
||||
guarantee. Existing source lookup/conversion helpers can be shared privately;
|
||||
no public registry, interface hierarchy, or constant-time guarantee is needed.
|
||||
|
||||
Alternative: keep only `Sources()`. That is sufficient for applications using
|
||||
the standard diagnostic renderer or building an index once. The addition can
|
||||
also wait until after v1, since it is compatible. Adding it with A1 is a small,
|
||||
coherent way to remove the same consumer bookkeeping on both outcomes of a load.
|
||||
|
||||
## N6. Make The Go Import Defaults More Self-Describing
|
||||
|
||||
Status: accepted. [api.md](api.md) owns the selected change; the discussion below
|
||||
preserves its rationale and alternative.
|
||||
|
||||
Evidence: [lifecycle.go](../../lifecycle.go) exposes `ImportDefaults.Follow` and
|
||||
`ImportDefaults.Hidden`. Their comments explain symbolic-link traversal and
|
||||
inclusion of hidden files/directories, but an options literal alone does not
|
||||
name the object being followed or say whether hidden entries are included.
|
||||
|
||||
Recommendation, at lower priority: consider `FollowSymlinks` and `IncludeHidden`
|
||||
for those Go fields. Preserve `*bool`, nil defaulting, explicit false, the current
|
||||
search scope, and the YAML keys `follow` and `hidden`. This would make the public
|
||||
Go configuration more descriptive without changing the import language. Leave
|
||||
`Required`, `Recursive`, and `Pattern` alone; they do not have the same ambiguity
|
||||
in context.
|
||||
|
||||
Alternative: retain the current Go names to mirror YAML exactly. That is a real
|
||||
benefit for readers moving between authored imports and application defaults,
|
||||
and existing comments already resolve the ambiguity. This is an optional naming
|
||||
refinement, weaker than N1's collision between two different path concepts.
|
||||
|
||||
## Discussion And Validation
|
||||
|
||||
All six findings have been accepted and incorporated into [api.md](api.md), with
|
||||
N4 folded into D6 and N5 into A1. This audit retains the review evidence and
|
||||
rationale; it is not an implementation plan or a permanent second API reference.
|
||||
|
||||
The review used the trusted catalog, root declarations and comments, current
|
||||
contracts and consumer guidance, and graph-assisted production-reference checks.
|
||||
No production code, tests, accepted decisions, or deferred features were changed.
|
||||
No independent behavioral audit or performance benchmarks were run. Validation
|
||||
for this document consists of the local documentation-link check and whitespace
|
||||
review; it is not evidence that the proposed API changes are implemented.
|
||||
@@ -6,14 +6,6 @@ plans, or release commitments. Adopting a candidate requires an explicit design
|
||||
decision and a separate plan. Significant architectural exclusions and their rationale belong
|
||||
in ADRs; this document does not maintain a list of rejected proposals.
|
||||
|
||||
## 1. Separate glob entry preparation from traversal
|
||||
|
||||
Implemented in the [internal-boundary roadmap](internal-boundaries.md#glob-entry-preparation) (C03).
|
||||
|
||||
## 2. Simplify redundant facade-to-engine transport
|
||||
|
||||
Implemented in the [internal-boundary roadmap](internal-boundaries.md#facade-to-engine-transport) (F07).
|
||||
|
||||
## 3. Recursive body merging for identified records
|
||||
|
||||
Status: deferred. The implemented
|
||||
@@ -91,3 +83,22 @@ evidence are preserved in Git history at `8e91a2b` under `docs/roadmap/`.
|
||||
across loads without introducing aliasing?
|
||||
- What cache lifetime and concurrency design would make schema reuse worthwhile
|
||||
without excessive retained memory?
|
||||
|
||||
## 6. Public path comparison
|
||||
|
||||
Status: deferred pending a concrete consumer need. This preserves A2 from the
|
||||
completed API review at `68400ff:docs/roadmap/review.md`.
|
||||
|
||||
`Path.String()` is a JSON Pointer spelling, not a complete semantic identity:
|
||||
an explicit numeric mapping key and a sequence index can share it. The public
|
||||
type is opaque and currently non-comparable.
|
||||
|
||||
If consumers need comparison, consider a small exact-representation operation
|
||||
rather than exposing mutable segments or introducing a pattern language. A
|
||||
proposal must distinguish exact segment representation, including parsed versus
|
||||
explicit segments and invalid state, from resolution against a document. Pointer
|
||||
string equality must not be presented as semantic equality.
|
||||
|
||||
Keeping `Path` solely as an opaque query/building value remains an alternative.
|
||||
No current contract changes or implementation commitment follow from this entry;
|
||||
a comparison operation can be added compatibly later.
|
||||
|
||||
@@ -1,498 +0,0 @@
|
||||
# Pre-v1 Public API Cleanup Implementation Plan
|
||||
|
||||
Status: complete; Stages 1–11 are complete.
|
||||
Baseline: `07e4ae5d9236935389e81b207d4a8f00543fafce`.
|
||||
Audience: a Luna coding agent executing the stages sequentially.
|
||||
|
||||
## Scope And Execution
|
||||
|
||||
Implement the accepted changes in the [API roadmap](api.md). That document owns
|
||||
the target, rationale, and behavioral boundaries. The revision-pinned
|
||||
[catalog](review.md) and [additional review](audit.md) preserve evidence and
|
||||
alternatives; they are not additional work lists. The preceding completed
|
||||
interface-remediation plan is preserved at
|
||||
`07e4ae5:docs/roadmap/implementation.md`. References in older audit records to
|
||||
that completed plan refer to its historical version, not this sprint.
|
||||
|
||||
This is one end-to-end sprint. Intermediate stages need not compile or leave a
|
||||
coherent repository. Do not create compatibility aliases, temporary public
|
||||
adapters, or intermediate releases to make individual stages green. Run focused
|
||||
checks when buildable and record deferred checks until they can actually run.
|
||||
Commit focused nonempty units under the [agent policy](../policy/agents.md),
|
||||
recording actual completion and validation below. A stage is not complete merely
|
||||
because its commands passed against the unchanged baseline.
|
||||
|
||||
Read `AGENTS.md`, the [development guide](../development.md), and applicable
|
||||
[architecture](../policy/architecture.md), [testing](../policy/testing.md), and
|
||||
[documentation](../policy/documentation.md) policies. Use graph-first discovery
|
||||
and check current references before editing. Preserve unrelated work.
|
||||
|
||||
The sprint changes Go names, removes selected public state, adds two passive
|
||||
queries, and changes exactly the two selected public strings. It does not change
|
||||
loading/composition, YAML syntax, version policy, callback auditing, history
|
||||
ownership, sensitivity, source acquisition, or secrets-bootstrap semantics.
|
||||
Do not add performance promises, restrictions, dependencies, release gates, or
|
||||
tests for incidental mechanics. Public path comparison (A2) remains deferred.
|
||||
Do not select a release version, write version-specific release notes, publish,
|
||||
or update external consumers in this sprint.
|
||||
|
||||
### Coverage Map
|
||||
|
||||
| Accepted item | Implementation owner |
|
||||
| --- | --- |
|
||||
| D1: `EntryInfo`; D2: `Sensitive` | Stage 1 |
|
||||
| D3: version policy/evidence vocabulary | Stage 2 |
|
||||
| D4: empty-selection records; D5: destination fallback name | Stage 3 |
|
||||
| N6: descriptive Go import defaults | Stage 4 |
|
||||
| N1: `SearchPaths`; D7: `LoadSecretsIntoEnvironment` | Stage 5 |
|
||||
| D6/N4: recording methods and invalid-kind diagnostic removal | Stage 6 |
|
||||
| N2: main-tier provenance name and string | Stage 7 |
|
||||
| N3: history-limit name/string; D8: unproduced diagnostic removal | Stage 8 |
|
||||
| A1/N5: successful and failed source lookup | Stage 9 |
|
||||
| Current guidance, migration information, integrated completion | Stages 10–11 |
|
||||
|
||||
### Private Implementation Choices
|
||||
|
||||
- Keep the public facade root-owned, with explicit forwarding and conversion.
|
||||
For facade-only renames, retain existing engine names unless steps below
|
||||
require a change. Root `Sensitive` can forward to engine `Secret`, and root
|
||||
`EntryInfo` can call engine `InputInfo`. Engine source-version records,
|
||||
import-default fields, discovery/bootstrap functions, and destination-fallback
|
||||
helpers need no cosmetic renames.
|
||||
- Remove empty-selection outcome state through its small private transport path.
|
||||
Keep candidate selection and admission decisions distinct from empty-selection
|
||||
evidence.
|
||||
- Replace root and engine kind-selecting `Resolution.Record` entry points with
|
||||
fixed-intent methods. Keep common `addRecord` and assignment helpers; remove
|
||||
the unreachable invalid-kind category after tracing remaining routes.
|
||||
- Use one engine-local slice lookup helper for new result/error queries. Scan
|
||||
the retained inventory and clone only a matching source with existing
|
||||
`cloneSourceInfo`; do not clone `Sources()` in full to search it. Keep the
|
||||
callback's existing indexed entry-state lookup unchanged. This is a private
|
||||
implementation choice, not a public complexity guarantee.
|
||||
- Rename main-layer and history-limit constants in both root and engine, so
|
||||
producers, conversion, and rendering use the selected strings directly.
|
||||
|
||||
### Validation Conventions
|
||||
|
||||
Commands run from the repository root using an installed compatible Go toolchain
|
||||
and already acquired dependencies. For Go checks use:
|
||||
|
||||
```sh
|
||||
export GOTOOLCHAIN=local
|
||||
export GOPROXY=off
|
||||
export GOTELEMETRY=off
|
||||
```
|
||||
|
||||
Keep disposable inventories outside the repository. Reuse behavioral tests for
|
||||
mechanical renames. Do not add negative-compilation fixtures or a permanent
|
||||
exported-symbol inventory test simply to prove old names disappeared; Stage 11
|
||||
performs a one-time review. Focused commands name existing test families and the
|
||||
proposed new lookup/recording cases. Include differently named new tests
|
||||
explicitly. A no-test match is not validation.
|
||||
|
||||
Update affected declaration comments and maintained Go callers, including
|
||||
examples, with each change. Stage 10 owns the integrated prose/migration sweep;
|
||||
it is not a reason to leave obvious neighboring comments wrong.
|
||||
|
||||
## Stage 1 — Clarify Resolution Entry Metadata And Sensitivity
|
||||
|
||||
Status: complete. Implements D1 and D2.
|
||||
|
||||
1. In [lifecycle.go](../../lifecycle.go), rename root `Resolution.InputInfo` to
|
||||
`EntryInfo` and `Definition.Secret` to `Sensitive`, without old aliases.
|
||||
Update `toEngineDefinition` to adapt the new predicate into engine `Secret`.
|
||||
Both loading entry points already share this conversion; retain that route.
|
||||
2. Keep `EntryInfo`'s existing `(FieldInfo, bool)` forwarding and silent
|
||||
unknown/invalid/shape-mismatch behavior. Its fixed entry view includes retained
|
||||
typed defaults and CLI assignments. Do not substitute final metadata or
|
||||
change `IsExplicit`'s separate schema-path validation behavior.
|
||||
3. Migrate root tests and maintained consumer calls. Update inactive-context
|
||||
cases in `facade_context_test.go`. Leave engine `InputInfo`, private
|
||||
sensitivity names, the `configkit:"secret"` tag, and typed `Secret` references
|
||||
unchanged. Do not broadly replace every identifier `Secret`.
|
||||
4. Reuse `facade_resolution_presence_test.go`, `facade_candidate_test.go`,
|
||||
`facade_context_test.go`, and existing secret/provenance owners. Preserve
|
||||
ordinary/container classification and its union with tags/dependencies.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'Resolution|InactiveContexts|FacadeLoad|Secret|Inspection|Diff' -count=1
|
||||
go test ./internal/engine -run 'Resolution|Provenance|Secret|Sensitivity' -count=1
|
||||
```
|
||||
|
||||
Completion: selected root names are in use; entry queries, lifecycle guards, and
|
||||
classification behavior are unchanged.
|
||||
|
||||
## Stage 2 — Rename Version Policy And Evidence
|
||||
|
||||
Status: complete. Implements D3.
|
||||
|
||||
1. Replace root `SourceVersionModeDefault` with `SourceVersionModeMainOnly`
|
||||
in the same zero slot in [lifecycle.go](../../lifecycle.go). Preserve numeric
|
||||
values and behavior of `IfPresent`/`Required` and the numeric engine bridge
|
||||
used by ordinary/layered loads.
|
||||
2. In [records.go](../../records.go), rename `SourceVersionCheck` to
|
||||
`SourceVersionEvidence` and `SourceInfo.VersionCheck` to `VersionEvidence`.
|
||||
Update [conversion.go](../../conversion.go); name its root-returning helper
|
||||
`fromEngineSourceVersionEvidence`, still accepting engine
|
||||
`SourceVersionCheck`. Preserve fields, nil handling, detached paths/locations,
|
||||
and sanitized text.
|
||||
3. Migrate Go callers/tests/examples and version comments together. `MainOnly`
|
||||
checks the effective path only with a configured rule; broader modes use
|
||||
source-local paths and require a usable rule. Evidence means observation,
|
||||
not acceptance or checker invocation. Add neither acceptance flags nor rules.
|
||||
4. Reuse `records_test.go` and `facade_source_version_mode_test.go`: zero-mode
|
||||
compatibility, missing-main checker invocation, absent non-main skipping,
|
||||
`NoSource`, explicit null, consumption, mounted/item coordinates, redaction,
|
||||
failure evidence, and detachment. Rename test names directly naming the
|
||||
replaced declaration; do not duplicate their case matrix.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'SourceVersion|VersionCheckConversion|VersionEvidenceConversion|Facade.*Version' -count=1
|
||||
go test ./internal/engine -run 'SourceVersion' -count=1
|
||||
```
|
||||
|
||||
Completion: all three replacements cross every source-record exposure correctly,
|
||||
with existing version behavior intact.
|
||||
|
||||
## Stage 3 — Simplify Empty-Selection And Destination Evidence
|
||||
|
||||
Status: complete. Implements D4 and D5.
|
||||
|
||||
1. Replace root `ImportSelection` with `EmptyImportSelection` and
|
||||
`SourceInfo.ImportSelections` with `EmptyImportSelections`. Retain `Path`,
|
||||
`Location`, and `Selector`; remove `Outcome`, `ImportSelectionOutcome`,
|
||||
and `ImportSelectionNone`. Keep `ImportSelector` and its three constants.
|
||||
2. Update root conversion/tests. In engine `records.go`, remove `Outcome`
|
||||
from `ImportSelectionForFacade`, the private evidence `outcome` field,
|
||||
and `importSelectionOutcomeString`. Remove its initializer in
|
||||
`import_acquisition.go` and the now-unused selection-outcome enum in
|
||||
`import_selection.go` after checking references. Its unused
|
||||
`importSelectionHasCandidates` member does not justify creating evidence.
|
||||
Preserve actual admission outcomes such as `importAdmissionOptionalMissing`,
|
||||
candidate handling, and accounting.
|
||||
Existing private transport/helper names may stay unchanged.
|
||||
3. Rename root `SourceInfo.DestinationUnresolved` to `DestinationIsFallback`.
|
||||
Conversion still reads existing private fallback evidence. Keep destination
|
||||
coordinates and placement modes; do not derive exact item coordinates where
|
||||
existing evidence does not contain them.
|
||||
4. Migrate root/internal assertions and maintained Go callers. Preserve empty
|
||||
selection scope/order, declaration-local paths, and copies on results,
|
||||
callbacks, and errors. Remove assertions of the retired outcome only, keeping
|
||||
real selection assertions. Reuse nested-item fallback/partial-failure cases;
|
||||
do not invent new placement states.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'ImportSelection|EmptyImport|Destination|SourceInfo|Fallback|RelativeImport' -count=1
|
||||
go test ./internal/engine -run 'ImportSelection|ImportEvidence|Import|Destination|Item' -count=1
|
||||
```
|
||||
|
||||
Completion: source records use the reduced record/new fields; selection,
|
||||
placement, partial evidence, and detachment retain established behavior.
|
||||
|
||||
## Stage 4 — Make Go Import Defaults Self-Describing
|
||||
|
||||
Status: complete. Implements N6.
|
||||
|
||||
1. Replace root `ImportDefaults.Follow` with `FollowSymlinks` and `Hidden`
|
||||
with `IncludeHidden`, preserving `*bool` and the other three fields.
|
||||
Update comments and `toEngineImportDefaults` to map to existing engine
|
||||
`Follow`/`Hidden`.
|
||||
2. Migrate root option literals, examples, and tests by type/context. Do not
|
||||
rename YAML `follow`/`hidden`, declaration parser fields, or unrelated
|
||||
hidden-file controls. Do not snapshot earlier in the facade: existing engine
|
||||
preflight owns the once-per-load snapshot before acquisition/callbacks.
|
||||
3. Reuse `facade_import_defaults_test.go` for nil, explicit false/true,
|
||||
transitive/underlay application, declaration overrides, pattern selection,
|
||||
and callback-mutation isolation. Preserve traversal/search scope and nil
|
||||
versus non-nil empty `Pattern`.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'ImportDefaults|ImportSelection|EmptyImport' -count=1
|
||||
go test ./internal/engine -run 'ImportDefaults|Import.*(Hidden|Follow|Symlink|Pattern)' -count=1
|
||||
```
|
||||
|
||||
Completion: descriptive Go fields feed unchanged YAML policy and snapshots in
|
||||
ordinary/layered loading.
|
||||
|
||||
## Stage 5 — Clarify Discovery And Environment Bootstrap Names
|
||||
|
||||
Status: complete. Implements N1 and D7.
|
||||
|
||||
1. In root [discovery.go](../../discovery.go), rename `Paths` to `SearchPaths`.
|
||||
Forward the same literal candidates to existing engine machinery. Migrate
|
||||
callers without touching semantic `Path`, `Keys`, or `Searches`. Retain
|
||||
order, deferred acquisition, and selected-file terminal failures.
|
||||
2. In root [secrets.go](../../secrets.go), rename `LoadSecretsDir` to
|
||||
`LoadSecretsIntoEnvironment`, preserving arguments, return values, error
|
||||
conversion, and engine bootstrap call. Comments should plainly describe
|
||||
explicit process-environment mutation, already-set/empty preservation,
|
||||
reports, and existing partial-application behavior.
|
||||
3. Migrate maintained calls, affected executable example identifiers, and nearby
|
||||
documentation. Do not couple bootstrap to `Load`, rename report/error types,
|
||||
or add filesystem/transactional guarantees. Process-mutating tests remain
|
||||
serial and restore state. Private engine function names may remain unchanged.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'Search|Discovery|SecretsBootstrap|LoadSecrets|Example_weatherStartup' -count=1
|
||||
go test ./internal/engine -run 'Search|Discovery|LoadSecretsDir' -count=1
|
||||
go test ./examples/consumers -run 'Discovery|WorkingDirectoryPreset|SequenceCatalog|Weather' -count=1
|
||||
```
|
||||
|
||||
Completion: old root functions are replaced outright; acquisition and safe
|
||||
bootstrap behavior remain unchanged.
|
||||
|
||||
## Stage 6 — Replace Kind-Selecting Recording With Intent Methods
|
||||
|
||||
Status: complete. Implements D6 and N4.
|
||||
|
||||
1. Replace root and engine `Resolution.Record` with:
|
||||
|
||||
```go
|
||||
RecordDerivedDefault(path Path, reason string, dependencies ...Path)
|
||||
RecordNormalization(path Path, reason string, dependencies ...Path)
|
||||
```
|
||||
|
||||
Root methods forward through existing live-context guards/path conversion.
|
||||
Engine methods call `activeState().addRecord` with their fixed
|
||||
`ChangeDerivedDefault` or `ChangeNormalization` and no helper expected
|
||||
value. Share existing validation/coalescing/auditing; neither method assigns
|
||||
values or tests absence.
|
||||
2. Migrate manual callers according to their existing supported kind in root
|
||||
tests, engine tests, examples, and current snippets. Leave `Default` and
|
||||
`Normalize` as assignment-and-recording helpers using existing `addRecord`
|
||||
routes. Retain `ChangeKind` and all inspection constants.
|
||||
3. Check every remaining `addRecord` caller supplies a supported fixed kind.
|
||||
Then remove the invalid-kind guard and `CodeResolveInvalidKind` from both
|
||||
root/engine. Remove only the obsolete arbitrary-kind case in
|
||||
`resolution_test.go`; retain invalid path, target, reason, dependency,
|
||||
projected-value, and unrecorded-change cases. If a legitimate supported
|
||||
public trigger remains, report it before changing its behavior.
|
||||
4. Update nil/zero/closed-context coverage for both methods. Add/adapt a small
|
||||
root case, `TestFacadeResolutionRecordingIntents`, proving each method's
|
||||
resulting origin/history kind after application assignment. Include explicit
|
||||
input changed and recorded as a derived default, so this cannot accidentally
|
||||
become the absence-checking helper. Reuse container coverage, overlapping
|
||||
records, repeated/equal intent, dependencies, and net-change tests elsewhere.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'Resolution|InactiveContexts|FacadeLoad|Historical|History' -count=1
|
||||
go test ./internal/engine -run 'Resolution|Provenance|Callback|History' -count=1
|
||||
```
|
||||
|
||||
Completion: root exposes only the selected manual recording methods; supported
|
||||
input cannot produce `resolve.invalid_kind`. Other auditing/lifetime behavior
|
||||
is unchanged.
|
||||
|
||||
## Stage 7 — Use Main Consistently In Provenance
|
||||
|
||||
Status: complete. Implements N2.
|
||||
|
||||
1. Replace `LayerBase = "base"` with `LayerMain = "main"` in root/engine
|
||||
records. Migrate producer references across acquisition, composition,
|
||||
decoding, inheritance origins, overrides, discovery, and history/rendering.
|
||||
Keep existing tier assignments.
|
||||
2. Review literal `"base"` provenance comparisons/rendered expectations, not just
|
||||
Go references. Update only the main-tier category. Filesystem base
|
||||
directories, domain values, fixture labels, and unrelated words are unchanged.
|
||||
Retain other layer spellings and source IDs/order.
|
||||
3. Update existing assertions in root, engine, and examples. Add a focused root
|
||||
records assertion for `string(LayerMain) == "main"`; reuse a public
|
||||
provenance/rendering fixture to verify main/imported-main attribution reaches
|
||||
consumers with that label. Imports retain their owning tier; other categories,
|
||||
precedence, and acquisition order are unchanged.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'Facade|Historical|History|Layer|PublicValues' -count=1
|
||||
go test ./internal/engine -run 'Compose|Overlay|Decode|Provenance|History|Explain|Grouped|Discovery' -count=1
|
||||
```
|
||||
|
||||
Completion: main-tier evidence/rendering consistently uses the selected constant
|
||||
and spelling without attribution/precedence changes.
|
||||
|
||||
## Stage 8 — Rename The History Diagnostic And Remove The Unused Code
|
||||
|
||||
Status: complete. Implements N3 and D8.
|
||||
|
||||
1. Replace root/engine `CodeExplainLimitExceeded` with
|
||||
`CodeHistoryLimitExceeded = "history.limit_exceeded"`. Update every producer,
|
||||
including `executeLoadRequest` in engine `load.go` and
|
||||
`inheritanceHistoryBudgetDiagnostic` in `inheritance_walk.go`, plus
|
||||
readers/literal assertions. Other explanation errors are unchanged.
|
||||
2. Reuse `history_budget_test.go` and inheritance-budget cases to preserve exact
|
||||
retained-node accounting and failure before effective secret lookup/application
|
||||
validation. Change expected code, not quota, fixtures, accounting, or timing.
|
||||
Add the new literal to focused root constant-value assertions, not a general
|
||||
API snapshot test.
|
||||
3. Reconfirm `CodeOptionsUnavailable`/`options.unavailable` has no producer or
|
||||
documented supported/reserved role. Baseline references are the two
|
||||
declarations and planning/review evidence. Remove both declarations. If a
|
||||
concrete supported role is discovered, bring it back for discussion rather
|
||||
than remove behavior or create a trigger. Other diagnostic codes stay intact.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test ./internal/engine -run 'HistoryBudget|RetainedNode|InheritanceExpansionEnforcesRetainedHistoryBudget' -count=1
|
||||
go test . -run 'PublicValues|LoadReturnsFacadeLoadError|Diagnostics|Historical' -count=1
|
||||
```
|
||||
|
||||
Completion: history failures carry the new code under unchanged conditions;
|
||||
D8's role check is resolved and its unproduced declaration is removed.
|
||||
|
||||
## Stage 9 — Add Detached Source Lookup On Results And Load Errors
|
||||
|
||||
Status: complete. Implements A1 and N5.
|
||||
|
||||
1. Add engine-local `lookupSourceInfo(sources []SourceInfo, id string)
|
||||
(SourceInfo, bool)` beside source cloning helpers. Return zero/false for
|
||||
empty/unknown IDs; otherwise scan the retained slice and clone the match.
|
||||
Add nil-safe engine `Inspection.Source` and `LoadError.Source` using it.
|
||||
Do not change inventories, query-time evidence, or the callback's source map.
|
||||
2. Add the selected root methods in [lifecycle.go](../../lifecycle.go) and
|
||||
[diagnostic.go](../../diagnostic.go):
|
||||
|
||||
```go
|
||||
func (r *Result[T]) Source(id string) (SourceInfo, bool)
|
||||
func (e *LoadError) Source(id string) (SourceInfo, bool)
|
||||
```
|
||||
|
||||
Return zero/false for nil or zero receivers/absent delegated state. Convert a
|
||||
found engine record through the Stage 2–3 `fromEngineSourceInfo` path.
|
||||
Keep enumeration, passive `SourceContext`, and callback `Source` intact.
|
||||
3. Document passive lookup, load-local IDs, detachment, and partial failed-load
|
||||
evidence. Read `LoadError`'s already-sanitized retained sources, not raw
|
||||
acquisition/version state. Do not complete placement, reinterpret absence
|
||||
as acceptance, open resources, or perform credential lookup.
|
||||
4. Add focused external-package tests `TestResultSourceLookup` and
|
||||
`TestLoadErrorSourceLookup`, or extend equivalent facade owners. Compare found
|
||||
records to enumeration; check empty/unknown IDs and nil/zero receivers.
|
||||
Mutate nested returned evidence and verify repeated lookup/enumeration are
|
||||
unchanged. Reuse import/version fixtures for `ImportedFrom`,
|
||||
`VersionEvidence.Location`, and empty-selection slices. Cover representative
|
||||
layered sources and failure evidence with redaction/partial placement.
|
||||
Reuse counting-resource fixtures where useful to demonstrate no query I/O;
|
||||
do not add a full load-mode matrix, timing assertions, or concurrency promises.
|
||||
|
||||
Focused validation:
|
||||
|
||||
```sh
|
||||
go test . -run 'SourceLookup|SourceVersionEvidence|ImportSelection|EmptyImport|SourceContext|Fallback' -count=1
|
||||
go test ./internal/engine -run 'SourceVersion|ImportSelection|Resource|ResolutionInput' -count=1
|
||||
```
|
||||
|
||||
Completion: both lookups agree with enumeration, return detached records, and
|
||||
preserve success/failure evidence without new load activity.
|
||||
|
||||
## Stage 10 — Complete Guidance And Consumer Migration Information
|
||||
|
||||
Status: complete. Consumer guidance, current contracts, declaration comments, and
|
||||
maintained examples use the selected API; historical report references identify
|
||||
their completed plan revision.
|
||||
|
||||
1. Review declaration comments and [config.md](../config.md)'s owning sections:
|
||||
discovery, import defaults/evidence, source versions, layered metadata,
|
||||
sensitivity, bootstrap, resolution, and history limits. Update relevant names
|
||||
and strings while preserving semantics. Keep detailed Go contracts beside
|
||||
declarations rather than reproducing them throughout prose.
|
||||
2. Migrate README, [consumer guidance](../consumers/README.md), root executable
|
||||
examples, and maintained `examples/` code/fixtures. Use new source lookup where
|
||||
an existing example enumerates solely to find an ID; retain enumeration where
|
||||
that is the task. Use new intent methods for manual recording while retaining
|
||||
assignment helpers where they do the work.
|
||||
3. Add a concise **Pre-v1 public API cleanup** subsection to the consumer guide's
|
||||
existing migration section. Include every old-to-new name from the roadmap,
|
||||
removed empty-selection outcome field/type/constant and diagnostic constants,
|
||||
both `Record` call rewrites, new lookups, and `"base"` → `"main"` /
|
||||
`"explain.limit_exceeded"` → `"history.limit_exceeded"`. Explain unchanged
|
||||
YAML `follow`/`hidden` and `configkit:"secret"`; literal comparisons and
|
||||
serialized expectations may need migration as well as Go code. Do not claim
|
||||
external migrations or select a version for this breaking pre-v1 work.
|
||||
4. Update internal docs only for changed descriptions. Do not rewrite accepted
|
||||
ADR decisions, pinned reviews, or historical release notes. If retained
|
||||
completed reports link to this overwritten plan, make their old-plan reference
|
||||
revision-specific rather than implying it concerns this sprint. Preserve
|
||||
unrelated proposals/status.
|
||||
|
||||
Validation:
|
||||
|
||||
```sh
|
||||
go test ./examples/consumers -count=1
|
||||
go test . -run '^Example|TestLocalDocumentationLinks' -count=1
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Validation passed with the commands above.
|
||||
|
||||
Completion: current guidance/examples use the selected API, migration information
|
||||
is complete, and historical evidence remains accurate.
|
||||
|
||||
## Stage 11 — Verify The Integrated Surface And Finish The Sprint
|
||||
|
||||
Status: complete. The root export audit matches the accepted table, D6/N4 and
|
||||
D8 reference checks are resolved, and the required focused and repository-wide
|
||||
checks passed.
|
||||
|
||||
1. Compare actual root exports/comments against the roadmap's complete accepted
|
||||
table using `go doc -all .` and, if needed, a disposable AST/type inventory
|
||||
outside the checkout. Check fields/method sets/constants as well as top-level
|
||||
names. Confirm both recording and lookup signatures and no removed root
|
||||
names/compatibility aliases.
|
||||
2. Search active Go callers/current documentation for old names and the two old
|
||||
strings. Review matches by context: retained private engine names, domain
|
||||
text, migration instructions, pinned reviews, and historical records are valid.
|
||||
Do not globally rewrite `base`, `Secret`, `Paths`, `Follow`, `Hidden`, or
|
||||
`Record`, or enforce a blanket zero-match rule. Recheck D6/N4 and D8 reference
|
||||
evidence against the final tree.
|
||||
3. Run deferred focused tests and existing boundary/link checks:
|
||||
|
||||
```sh
|
||||
go test . -run 'TestPublicFacadeBoundary|TestDependencyImportBoundary|TestLocalDocumentationLinks' -count=1
|
||||
./scripts/check.sh
|
||||
```
|
||||
|
||||
Validation passed: the focused boundary/link test and `./scripts/check.sh`.
|
||||
`go doc -all .` confirmed the selected root fields, constants, methods, and
|
||||
signatures; removed root names and old diagnostic strings were absent.
|
||||
Graph tracing showed `addRecord` is called only by the two fixed-intent
|
||||
methods and the assignment helpers. No Go declaration or use of either
|
||||
removed diagnostic remains.
|
||||
|
||||
The everyday check already runs the full default suite, vet, and build,
|
||||
including examples. No additional full-suite pass or benchmarks are needed
|
||||
solely for this plan. If implementation changed mutable ownership/concurrency
|
||||
beyond forwarding/existing clone paths, follow the development guide with
|
||||
`go test -race ./...`; record the reason/result. This introduces no permanent
|
||||
release gate and requires no CI waiting.
|
||||
4. Inspect the final diff for unselected semantics, ownership changes,
|
||||
dependencies, artifacts, and strengthened guarantees. Record actual stage
|
||||
completion/validation here. Mark the API roadmap implemented only after its
|
||||
selected surface and behavior preservation are verified. Keep completed
|
||||
planning/review records until normal release preparation. Commit completed
|
||||
nonempty units with plain-English messages; report remaining work accurately.
|
||||
|
||||
Completion: all accepted items are implemented, diagnostic role/reachability
|
||||
checks are resolved, applicable checks pass, and current docs/examples agree.
|
||||
No unselected public or semantic changes remain. This is implementation
|
||||
completion, not release publication or external consumer verification.
|
||||
|
||||
## Decision Status
|
||||
|
||||
No open design question is required to execute this plan. D8's role check and
|
||||
D6/N4's reachability check are verification tasks with an explicit discussion path
|
||||
if unexpected supported use is found. Private helper naming may be adjusted for
|
||||
cohesion without changing the selected surface or behavior.
|
||||
@@ -1,337 +0,0 @@
|
||||
# Interface Contract Remediation Roadmap
|
||||
|
||||
Status: implemented. The shared history owner and all four audit corrections
|
||||
are complete; validation is recorded in the completed plan at
|
||||
`07e4ae5:docs/roadmap/implementation.md`.
|
||||
Planning baseline: `1f64673` (v0.10.2 implementation plus documentation changes).
|
||||
|
||||
This roadmap covers the four findings in the [interface audit](interfaces.md).
|
||||
The audit owns reproductions, evidence, and finding numbers. This document owns
|
||||
the combined target, required changes, and design intent. The completed plan at
|
||||
`07e4ae5:docs/roadmap/implementation.md` records concrete stages, private
|
||||
implementation choices, validation commands, and progress.
|
||||
|
||||
## Purpose And Scope
|
||||
|
||||
Restore agreement between ConfigKit's presence, metadata, history, and diagnostic
|
||||
interfaces under their existing contracts. The first three findings concern
|
||||
semantic paths that share a JSON Pointer spelling; the fourth concerns a
|
||||
composition claimant order that is lost during diagnostic canonicalization.
|
||||
|
||||
Build one shared internal history model from which metadata history and
|
||||
explanation are derived. It will own the historical evidence and semantic
|
||||
attribution used by both views, replacing their independent reconstruction of
|
||||
that attribution. This is the selected resolution of OD-1.
|
||||
|
||||
The [Path declarations](../../path.go), [metadata contract](../config.md#layered-metadata),
|
||||
[resolution contract](../config.md#recorded-application-resolution), and
|
||||
[strict-composition contract](../config.md#strict-document-composition) remain
|
||||
authoritative. This work changes the implementation of those contracts without
|
||||
selecting a new public API, path syntax, precedence rule, or configuration
|
||||
restriction. The existing root-owned facade and engine responsibilities remain.
|
||||
|
||||
## Current Baseline And Targeted End State
|
||||
|
||||
An explicit mapping-key path and an explicit sequence-index path can both render
|
||||
as `/shape/0`. `ParsePath` deliberately leaves numeric tokens contextual, whereas
|
||||
`Keys` and `Index` preserve the caller's explicit choice. The engine already has
|
||||
shape-aware effective/historical path indexes and a frozen resolution-entry view,
|
||||
but some queries and metadata updates still use pointer spelling alone.
|
||||
|
||||
History currently reconstructs definition and previous-origin records, while
|
||||
explanation replays source contributions, inheritance, decoding checkpoints, CLI
|
||||
assignments, and grouped resolution snapshots. Neither public representation
|
||||
contains everything needed by the other. The target is shared underlying evidence
|
||||
with distinct projections for each interface, preserving their existing behavior.
|
||||
|
||||
| Finding | Current discrepancy | Target |
|
||||
| --- | --- | --- |
|
||||
| 1: resolution presence | `IsExplicit` and `Default` consult string-keyed presence after schema validation, which cannot determine actual shape beneath dynamic values. | Presence decisions use the matching semantic path in the fixed resolution-entry state. |
|
||||
| 2: effective explicitness | Resolution retains old field information when pointer spelling survives a container-shape change. | Input explicitness carries forward for the same semantic path; a newly introduced key or index does not inherit another path's explicitness. |
|
||||
| 3: history attribution | A historical-shape check admits the query, then `History` returns the entire textual-pointer bucket; explanation selects evidence separately. | Both interfaces derive attribution from one shared history model, selecting exact definitions, previous origins, and applicable ancestor operations by semantic path. |
|
||||
| 4: claimant order | Composition constructs related locations in assembly order, then canonicalization sorts them by location. | Structured and rendered composition conflicts preserve the selected claimant order. |
|
||||
|
||||
For example, if input contains `shape: {'0': old}` and recorded application
|
||||
resolution changes `shape` to a sequence, the old key remains an input path in
|
||||
the callback's entry view. The new index is effective in final metadata but was
|
||||
not explicitly supplied by that input. Its history must not present the old key's
|
||||
definition as its own. This distinction concerns container shape, not identity
|
||||
tracking for records that move within a sequence.
|
||||
|
||||
## Required Changes
|
||||
|
||||
### 1. Use Entry-State Shape For Resolution Presence
|
||||
|
||||
In [resolution.go](../../internal/engine/resolution.go), align `IsExplicit` and
|
||||
the explicitness decision in `Default` with the frozen, shape-aware entry metadata
|
||||
already used by `InputInfo` in
|
||||
[load_metadata.go](../../internal/engine/load_metadata.go).
|
||||
|
||||
Reuse the existing semantic-path matching machinery. A shared private lookup can
|
||||
avoid divergent presence decisions without requiring every public query to have
|
||||
identical error behavior. In particular:
|
||||
|
||||
- Preserve `IsExplicit`'s schema-path validation and its existing diagnostics.
|
||||
`InputInfo` remains a query that returns false for missing or mismatched paths
|
||||
without those diagnostics.
|
||||
- Preserve `Default`'s helper-target validation, assignment, recording, and final
|
||||
helper-value checks. Correct its presence gate; do not bypass the other checks.
|
||||
- Use entry-state shape even after application code changes the working value.
|
||||
Explicit false, zero, empty, and null retain their existing presence meaning.
|
||||
- Keep callback lifetime and detached metadata behavior intact.
|
||||
|
||||
A shape mismatch beneath a schema-valid dynamic path must not become explicit
|
||||
merely because its pointer spelling matches an input path. Contextually parsed
|
||||
numeric tokens continue to resolve against the entry state's actual containers.
|
||||
|
||||
### 2. Preserve Explicitness By Semantic Path During Resolution
|
||||
|
||||
Update resolution metadata application and field refresh in
|
||||
[load_metadata.go](../../internal/engine/load_metadata.go) to compare the relevant
|
||||
entry and final shapes before reusing presence information.
|
||||
|
||||
The comparison must account for container kinds along the full path. A mapping
|
||||
key becoming a sequence index at an ancestor can change a descendant's semantic
|
||||
path even when its last segment and full pointer spelling stay unchanged.
|
||||
|
||||
Keep explicitness for matching surviving paths, including descendants covered by
|
||||
an ancestor normalization record. New semantic paths introduced by resolution
|
||||
remain non-explicit, and retain the applicable recorded resolution origin.
|
||||
Removed paths leave effective metadata while remaining available to historical
|
||||
queries under the existing contract. Do not clear every descendant's presence
|
||||
just because its parent was normalized.
|
||||
|
||||
Use the existing before/after projection and entry metadata where possible.
|
||||
This work does not require tracking every transient mutation inside a callback;
|
||||
the existing net-change and coalesced-record model continues to apply.
|
||||
|
||||
### 3. Build A Shared Internal History Model
|
||||
|
||||
#### Evidence And Ownership
|
||||
|
||||
Give historical evidence one private owner in the engine. Composition,
|
||||
inheritance, decoding, CLI assignment, and resolution continue to perform their
|
||||
existing work and supply evidence to that owner. The model does not drive a
|
||||
second configuration load or repeat application callbacks.
|
||||
|
||||
Organize the evidence into ordered groups with the phase boundaries required by
|
||||
the existing inspection contracts:
|
||||
|
||||
| Evidence group | Information to preserve |
|
||||
| --- | --- |
|
||||
| Default baseline | Canonical typed application defaults or Go-zero values and their default attribution. |
|
||||
| Source contributions | Underlay, main-tier, and selected-overlay contributions in their existing order; exact definitions, composite origins, displaced definitions, raw policy-validated values, and sequence-position projections. |
|
||||
| Inheritance | Parent transfers, child contributions including equal-valued replacements, controlling directives and their consumption, identity-field preservation, and contribution origins/dependencies. |
|
||||
| Typed checkpoints | Pre-CLI and post-CLI typed projections and attribution needed to reconcile retained defaults and raw contributions with decoded values. |
|
||||
| CLI contributions | Explicit assignments, including equal-valued assignments, raw supplied representation, source attribution, and affected paths. |
|
||||
| Resolution | Original recorded operations, reasons, dependencies, and before/after evidence, with the grouping needed to explain overlapping records as net subtree changes. |
|
||||
|
||||
The logical order remains baseline, source contributions, inheritance, pre-CLI
|
||||
decoding reconciliation, CLI contributions, post-CLI typed reconciliation, then
|
||||
recorded resolution. The two typed checkpoints belong on their respective sides
|
||||
of the CLI contribution phase.
|
||||
|
||||
The groups describe logical inspection chronology, not a transcript of every
|
||||
physical mutation. Retain the existing net-change and coalescing rules for
|
||||
resolution. Preserve superseded raw input that need not decode into the final
|
||||
application type; typed checkpoints do not replace that evidence.
|
||||
|
||||
Use a small set of ordinary private structures and existing document/path
|
||||
mechanisms. Exact types, indexes, and storage layout belong in the implementation
|
||||
plan. Complete evidence means enough for the existing history, explanation, and
|
||||
internal attribution consumers; it does not add persistence, a public event API,
|
||||
or recording of transient application effects.
|
||||
|
||||
#### Shared Selection And Attribution
|
||||
|
||||
Retain concrete semantic-path evidence when it is available. A query over the
|
||||
model must distinguish exact definitions from operations affecting an ancestor
|
||||
or descendant, determine the relevant previous origins, and apply sequence
|
||||
contribution coordinates at their assigned positions.
|
||||
|
||||
The affected semantic path and the operation's reported path are distinct facts.
|
||||
For example, a replacement at `/shape` can remove a mapping key and introduce a
|
||||
sequence index with the same pointer spelling. Preserve enough before/after shape
|
||||
evidence to answer each explicit query correctly. Merely filtering `Change.Path`
|
||||
after concrete segment kinds have been discarded is insufficient.
|
||||
|
||||
Make this selection and attribution common to both projections, including
|
||||
inheritance integration and `Previous` reconstruction. A false definition must
|
||||
not survive as a previous origin after it has been excluded from the query's
|
||||
history. Preserve genuine ancestor replacement/removal effects and chronology.
|
||||
A path that never existed does not acquire history solely because an ancestor
|
||||
changed.
|
||||
|
||||
Keep the contextual meaning of parsed numeric tokens across historical states
|
||||
and the one-entry-per-canonical-pointer enumeration of `HistoricalPaths`.
|
||||
Historical-path membership and enumeration must also derive from the shared
|
||||
evidence. Preserve the existing inventory of default-only paths, displaced
|
||||
descendants, consumed inheritance controls, and historical mapping-key and
|
||||
sequence-index shapes, including evidence that a public projection coalesces or
|
||||
omits. Indexes and compact derived records may remain, but their membership and
|
||||
attribution must come from that evidence. Metadata queries should not require
|
||||
full configuration replay or YAML rendering to obtain definition and origin
|
||||
records.
|
||||
|
||||
#### Distinct Public Projections
|
||||
|
||||
`Metadata.History` produces detached definition, inheritance, and resolution
|
||||
records from the model. `Explain` reconstructs and safely renders values from
|
||||
the same evidence, retaining its existing decoding and grouping behavior. Neither
|
||||
public API should be implemented by translating the other's public result.
|
||||
|
||||
Preserve these intentional differences:
|
||||
|
||||
| Case | Metadata history | Explanation |
|
||||
| --- | --- | --- |
|
||||
| Several strict contributions to a mapping | Composite definition/origin information. | Each contribution's effect on the mapping. |
|
||||
| Raw input differs from canonical typed values | Definition and attribution records. | The applicable decoding reconciliation transition. |
|
||||
| Overlapping resolution records | Specific recorded attribution under the existing coverage rules. | One net subtree event with combined reasons and dependencies. |
|
||||
| Equal-valued input or inheritance operations | Explicit definition and operation attribution remains visible. | Relevant operations remain visible even when before and after values are equal. |
|
||||
|
||||
Agreement means consistent semantic identity and attribution, not identical
|
||||
record lists. Retain original resolution records as evidence from which net
|
||||
replay groups are derived; a grouped explanation alone loses information needed
|
||||
by metadata.
|
||||
|
||||
#### Replace Existing Attribution Machinery
|
||||
|
||||
The common model must replace independent historical attribution, rather than
|
||||
become another representation alongside it. The completed plan at
|
||||
`07e4ae5:docs/roadmap/implementation.md` mapped the following owners to their
|
||||
replacements:
|
||||
|
||||
| Current owner | Required change |
|
||||
| --- | --- |
|
||||
| History-building portions of `metadataFromDecoded`, `applyOverlayMetadata`, and `appendPostDecodeCLIHistory` in [load_metadata.go](../../internal/engine/load_metadata.go) and [override_context.go](../../internal/engine/override_context.go) | Produce or project shared evidence instead of independently reconstructing pointer-keyed histories. Retain effective-field construction where it is still needed. |
|
||||
| Resolution-history construction in `applyResolutionMetadata` and `appendResolutionDescendantHistory` in [load_metadata.go](../../internal/engine/load_metadata.go) | Derive resolution records and previous origins through common semantic selection and attribution. Retain the effective-field updates still needed by final metadata. |
|
||||
| Historical-path inventory in `finalizeMetadataPaths` in [metadata.go](../../internal/engine/metadata.go) | Derive historical membership, shape indexes, and enumeration from the shared evidence while preserving the existing path inventory. Retain effective-path indexing where needed. |
|
||||
| Previous-origin reconstruction and inheritance insertion in [inheritance_history.go](../../internal/engine/inheritance_history.go) | Use common semantic selection and attribution while preserving the existing inheritance projection rules. |
|
||||
| Relevance and chronology orchestration in [explain.go](../../internal/engine/explain.go) | Consume the shared model; retain useful value reconstruction and redaction helpers. |
|
||||
| Separate published inheritance evidence for metadata and explanation in [load_result.go](../../internal/engine/load_result.go) | Consolidate under the frozen history owner where independent copies are unnecessary; keep required output detachment. |
|
||||
| Original and coalesced resolution evidence in [history.go](../../internal/engine/history.go) | Own original records in the model and derive the replay grouping without losing specific attribution or maintaining a second independently interpreted history. |
|
||||
|
||||
Existing source, sequence-combination, and inheritance evidence producers may
|
||||
remain useful. Their algorithms need not be rewritten merely to contribute to
|
||||
the model. Likewise, final effective fields, the frozen resolution-entry view,
|
||||
source records, and final configuration snapshots retain their responsibilities.
|
||||
Findings 1 and 2 still require explicit presence corrections.
|
||||
|
||||
#### Other Consumers, Lifetime, And Resource Accounting
|
||||
|
||||
Move historical dependency reads in
|
||||
[secret classification](../../internal/engine/secret.go) and historical location
|
||||
fallbacks in [override_context.go](../../internal/engine/override_context.go) to
|
||||
the shared evidence. Do not retain the old history machinery solely for those
|
||||
readers. Preserve existing sensitivity propagation and historical classification;
|
||||
correcting attribution does not authorize narrowing redaction for paths that
|
||||
share a pointer spelling.
|
||||
|
||||
Evidence must be available at the lifecycle stages where these internal readers
|
||||
need it, including diagnostic attribution before publication. Keep the callback's
|
||||
entry metadata fixed while later resolution evidence is added. Finalize the
|
||||
model for published queries without introducing lazy mutation of shared state.
|
||||
Private frozen evidence may be shared by the two views while their returned
|
||||
records remain detached under the existing ownership contract.
|
||||
|
||||
Reuse retained trees and existing lookup machinery where practical. Review
|
||||
retained-history accounting against the resulting ownership graph, including
|
||||
typed checkpoints and inheritance/resolution evidence. The model does not require
|
||||
a full document copy per event, a new quota, or a new concurrency guarantee.
|
||||
Reduced duplication is a design benefit to evaluate, not a promised memory or
|
||||
speed improvement.
|
||||
|
||||
Preserve final retained-history budget admission before effective secret lookup
|
||||
and application validation. Do not defer that check to publication or a later
|
||||
query. Count the resulting retained ownership graph; tests should exercise its
|
||||
budget boundary and failure timing without requiring obsolete duplicate copies
|
||||
or the old representation's exact node totals.
|
||||
|
||||
### 4. Preserve Composition Claimant Order Through Diagnostics
|
||||
|
||||
Keep the order produced by `compositionConflictDiagnostic` in
|
||||
[compose.go](../../internal/engine/compose.go) through accumulation, `LoadError`,
|
||||
facade conversion, and `WriteDiagnostics` in
|
||||
[diagnostic.go](../../internal/engine/diagnostic.go).
|
||||
|
||||
Prefer a narrow internal canonicalization rule based on the diagnostic semantics
|
||||
already carried across these boundaries. Identify the composition diagnostic
|
||||
producers governed by the claimant-order contract rather than changing all
|
||||
related-location lists. Preserve canonical ordering of diagnostic records and
|
||||
the existing sorting of related locations for other diagnostics.
|
||||
|
||||
The root renderer converts public diagnostic records back to engine records and
|
||||
canonicalizes them again. An engine-only marker discarded by facade conversion
|
||||
would therefore be insufficient. No public ordering option is needed for this
|
||||
correction. Keep primary selection, conflict detection, acquisition order, and
|
||||
dependency-ready scheduling unchanged.
|
||||
|
||||
## Validation And Completion
|
||||
|
||||
Follow the [testing policy](../policy/testing.md) and use the
|
||||
[development guide](../development.md#baseline-validation) for checks. Extend
|
||||
existing test owners rather than recreating full internal matrices at the facade.
|
||||
The focused cases should cover:
|
||||
|
||||
- Both mapping-key/index mismatch directions beneath dynamic values, including
|
||||
explicit paths and contextual parsed pointers. Check callback presence and
|
||||
`Default` behavior, including the fixed entry view after working-value changes.
|
||||
- Both container-shape transitions during recorded resolution, a descendant
|
||||
affected by an ancestor shape change, and a same-shape normalization control.
|
||||
Check explicitness and recorded origins through final metadata and explanation.
|
||||
- Shape-changing CLI and resolution history, checking exact definitions,
|
||||
`Previous`, and genuine ancestor replacement/removal. Include contextual
|
||||
enumeration/query coverage, including historical paths whose evidence is
|
||||
coalesced or omitted by a public projection. Preserve existing inheritance and
|
||||
overlay cases; add another case only where those integrations expose an
|
||||
unprotected risk.
|
||||
- Shared-model projections across composite mapping origins, typed decoding and
|
||||
default reconciliation, equal-valued writes, inheritance controls/transfers,
|
||||
mapped sequence replacements and removed descendants, and overlapping
|
||||
resolution records. Reuse existing cases where they protect those semantics;
|
||||
check the intentional differences between the public projections as well as
|
||||
agreement on attribution.
|
||||
- Historical sensitivity/dependency propagation, diagnostic source-location
|
||||
fallback, detached returned records, and complete retained-history accounting
|
||||
under the new ownership graph. Preserve budget rejection before effective
|
||||
secret lookup and application validation. Use small controlled budget cases
|
||||
and existing disclosure fixtures rather than memory or timing thresholds.
|
||||
- A composition conflict whose acquisition and assembly orders differ, using the
|
||||
audit fixture. Check both published diagnostics and rendered related-location
|
||||
order, while retaining coverage for ordinary diagnostic canonicalization.
|
||||
|
||||
Retain existing checks for invalid schema paths, callback lifetime, detached
|
||||
records, safe historical rendering, and default/null presence semantics. Test
|
||||
observable behavior rather than a particular private index or number of copies.
|
||||
No benchmark campaign, broader audit, or new release gate is part of this roadmap.
|
||||
|
||||
Completion requires all four findings to have implementation and regression
|
||||
evidence, appropriate development checks, and both history interfaces deriving
|
||||
semantic attribution from the shared model. Review the final producer/consumer
|
||||
map to confirm superseded independent reconstruction has been removed,
|
||||
historical-path discovery derives from shared evidence, and internal attribution
|
||||
readers have migrated. Passing the four defect regressions while retaining the
|
||||
old parallel attribution machinery is not completion.
|
||||
|
||||
The audit's previous passing suite is not validation of these future changes.
|
||||
Scope here does not promise identical output from different inspection interfaces
|
||||
or a universal guarantee about unrelated path-processing code.
|
||||
|
||||
## Decision Status
|
||||
|
||||
OD-1 is settled: build one shared internal history model with distinct metadata
|
||||
and explanation projections. The design investigation found that both views
|
||||
require evidence the other's public representation does not preserve. Shared
|
||||
ownership can replace independent attribution and redundant retained evidence,
|
||||
while keeping the current lifecycle and public contracts.
|
||||
|
||||
The narrower repair of stored history events would leave the separate replay
|
||||
attribution owner in place. Promoting current explanation output to authoritative
|
||||
history would lose composite-definition and specific resolution information.
|
||||
The selected common underlying model addresses both concerns. This accepts a
|
||||
larger internal refactor than a local shape-filtering fix.
|
||||
|
||||
No significant open decision remains at roadmap level. Private representation,
|
||||
indexing, and helper choices are recorded in the completed plan at
|
||||
`07e4ae5:docs/roadmap/implementation.md`.
|
||||
This roadmap does not revise accepted ADRs.
|
||||
@@ -1,213 +0,0 @@
|
||||
# API and Interface Contract Audit
|
||||
|
||||
Reviewed baseline: `01b08e76a3fecc22c4414437bfeaa07b4b7a85aa`.
|
||||
|
||||
Status: all four findings resolved. This remains an audit record, not an
|
||||
implementation plan; resolution evidence is recorded with each finding.
|
||||
|
||||
The [interface remediation roadmap](interface-remediation.md) describes the
|
||||
settled target and its dependencies, including a shared internal history model
|
||||
for metadata history and explanation. The completed implementation and
|
||||
integrated validation are recorded at
|
||||
`07e4ae5:docs/roadmap/implementation.md`.
|
||||
This audit retains the findings and original reproduction evidence.
|
||||
|
||||
## Scope and evidence
|
||||
|
||||
Reviewed the root-owned public facade and its conversions, engine loading and
|
||||
callback boundaries, source/discovery and filesystem ownership, schema and typed
|
||||
value handling, metadata/history, safe rendering and comparison, secrets, and
|
||||
the document/YAML boundary against declaration comments, the
|
||||
[configuration contract](../config.md), and applicable architectural decisions.
|
||||
The root delegates to the synchronous engine lifecycle; parser-independent
|
||||
documents support source assembly and inheritance, and completed results retain
|
||||
detached configuration and frozen inspection state.
|
||||
|
||||
The findings below were reproduced through the public API with a disposable Go
|
||||
program outside the repository, using labeled byte sources and `fstest.MapFS`.
|
||||
The full existing suite passed with Go 1.26.10 on Linux:
|
||||
|
||||
```sh
|
||||
GOTOOLCHAIN=local GOTELEMETRY=off GOPROXY=off go test ./... -count=1
|
||||
```
|
||||
|
||||
The existing tests cover many ownership, lifetime, error, and zero-value cases,
|
||||
but do not detect these cross-interface discrepancies. No benchmarks, external
|
||||
service calls, or new test files were needed. The recommendations restore
|
||||
existing contracts rather than introduce new API restrictions or guarantees.
|
||||
|
||||
## 1. Resolution presence queries confuse explicit keys with sequence indexes
|
||||
|
||||
Priority: P2. Status: resolved. Evidence: `TestFacadeResolutionPresenceUsesDynamicEntryShape`,
|
||||
the engine resolution/provenance/default regressions, and the integrated checks
|
||||
recorded at `07e4ae5:docs/roadmap/implementation.md`.
|
||||
|
||||
Relevant code:
|
||||
|
||||
- [`Resolution.IsExplicit`](../../internal/engine/resolution.go), lines 75–82.
|
||||
- `Resolution.InputInfo` and `resolutionInput.lookup` in
|
||||
[resolution.go](../../internal/engine/resolution.go) and
|
||||
[load_metadata.go](../../internal/engine/load_metadata.go).
|
||||
- `resolveSchemaPath` in [schema.go](../../internal/engine/schema.go).
|
||||
|
||||
The public [path contract](../../path.go) distinguishes explicit mapping keys
|
||||
from sequence indexes. The [resolution contract](../config.md#recorded-application-resolution)
|
||||
defines surviving-input presence and a fixed entry-state metadata view;
|
||||
[metadata queries](../config.md#layered-metadata) preserve container shapes.
|
||||
|
||||
`IsExplicit` validates against the schema but then looks up presence using only
|
||||
`path.String()`. In dynamic `any` state, schema validation cannot establish the
|
||||
actual container shape. Consequently these distinct queries collide:
|
||||
|
||||
```go
|
||||
key := configkit.Keys("shape", "0")
|
||||
index := configkit.Keys("shape").Index(0)
|
||||
```
|
||||
|
||||
Load `map[string]any` from `shape: [input]` with a resolver that queries both
|
||||
paths, without changing the configuration. Observed results:
|
||||
|
||||
| Query | `Resolution.IsExplicit` | `Resolution.InputInfo` found | Final `Metadata.IsExplicit` |
|
||||
| --- | --- | --- | --- |
|
||||
| Explicit mapping key | true | false | false |
|
||||
| Explicit sequence index | true | true | true |
|
||||
|
||||
The mapping-key path never existed and should not be reported as explicit.
|
||||
Applications branching on presence receive inconsistent answers depending on
|
||||
which public query they use, even during an otherwise unchanged load.
|
||||
|
||||
Potential remediation: use the retained entry-state semantic shape when checking
|
||||
resolution presence, consistently with `InputInfo` and `Metadata.IsExplicit`.
|
||||
Review the same string-only presence lookup in `Default` while preserving its
|
||||
existing assignment and callback-lifetime rules. Add focused public coverage for
|
||||
both mapping-to-index and index-to-mapping mismatches under dynamic values,
|
||||
including contextually parsed pointers. This does not require changing the
|
||||
documented treatment of invalid schema paths.
|
||||
|
||||
## 2. Resolution can transfer explicitness to a different semantic path
|
||||
|
||||
Priority: P2. Status: resolved. Evidence: the engine resolution/metadata/provenance
|
||||
regressions, the full engine suite, and the integrated checks recorded at
|
||||
`07e4ae5:docs/roadmap/implementation.md`.
|
||||
|
||||
Relevant code: `applyResolutionMetadata`, `applyResolutionFieldOrigins`, and
|
||||
`refreshResolutionFields` in
|
||||
[load_metadata.go](../../internal/engine/load_metadata.go), especially lines
|
||||
371–387; final shape checking in
|
||||
[`Metadata.effectiveField`](../../internal/engine/metadata.go).
|
||||
|
||||
The [metadata contract](../config.md#layered-metadata) distinguishes key/index
|
||||
shapes and keeps derived values for absent input non-explicit. Recorded
|
||||
resolution changes origins without creating input explicitness.
|
||||
|
||||
Reproduction:
|
||||
|
||||
1. Load `map[string]any` from `shape: {'0': old}`.
|
||||
2. In resolution, replace `configuration["shape"]` with `[]any{"new"}` and
|
||||
record normalization at `Keys("shape")`.
|
||||
3. Query final metadata using the two paths from finding 1.
|
||||
|
||||
The old explicit mapping-key path correctly stops being effective, but the newly
|
||||
created sequence index reports `Explicit: true`. That sequence index was never
|
||||
supplied by input. `refreshResolutionFields` reuses the old `FieldInfo` whenever
|
||||
its textual pointer survives; it updates null state without checking whether
|
||||
the old and new containers give that pointer different semantic shapes. Final
|
||||
lookup validates only the new shape, so it cannot recover the lost distinction.
|
||||
|
||||
This can mislead consumers inspecting whether a final value was explicitly
|
||||
configured rather than introduced by application resolution. The converse
|
||||
sequence-to-numeric-key transition has the same underlying collision.
|
||||
|
||||
Potential remediation: retain entry/effective shape evidence across resolution
|
||||
and carry input explicitness forward only for the matching semantic path.
|
||||
Preserve existing explicitness for same-shape paths and the recorded resolution
|
||||
origin; do not clear every descendant's presence merely because an ancestor was
|
||||
normalized. Cover both shape transitions and agreement among `Lookup`,
|
||||
`IsExplicit`, and explanation. Fixing finding 1's callback query alone does not
|
||||
repair this publication path.
|
||||
|
||||
## 3. Metadata history mixes numeric-key and sequence-index definitions
|
||||
|
||||
Priority: P2. Status: resolved. Evidence: `TestPublicHistoryUsesResolutionShapeAttribution`,
|
||||
`TestPublicHistoricalPathsEnumerateContextualShapes`, shared history-selection
|
||||
and explanation regressions, and the integrated checks recorded at
|
||||
`07e4ae5:docs/roadmap/implementation.md`.
|
||||
|
||||
Relevant code:
|
||||
|
||||
- [`Metadata.History`](../../internal/engine/metadata.go), lines 56–65.
|
||||
- `metadataFromDecoded`, `applyOverlayMetadata`, and history event construction
|
||||
in [load_metadata.go](../../internal/engine/load_metadata.go).
|
||||
- Shape-aware replay in [`Inspection.Explain`](../../internal/engine/explain.go).
|
||||
|
||||
The [metadata contract](../config.md#layered-metadata) promises semantic
|
||||
key/index distinctions for historical as well as effective queries. The
|
||||
historical-path index retains both shapes, but `History` uses that index only to
|
||||
check that the query was ever known. It then retrieves the entire history bucket
|
||||
by textual pointer, without selecting the query's shape.
|
||||
|
||||
Reproduction: load `shape: {'0': old}` into `map[string]any`, then apply a CLI
|
||||
override at `Keys("shape")` with `[]any{"new"}`. Both explicit shapes were
|
||||
observed and share `/shape/0`.
|
||||
|
||||
`History(Keys("shape").Index(0))` incorrectly includes the original base
|
||||
definition of the mapping key, and identifies that base origin as the previous
|
||||
origin of the CLI operation. The old input defined a key, not an index. In the
|
||||
same successful result, `Explain` for the explicit index correctly shows only
|
||||
its CLI introduction. `History` for the key and index returns identical records
|
||||
despite their different lifetimes.
|
||||
|
||||
Consequences include false source attribution and disagreement between the two
|
||||
public history interfaces when consumers inspect removed or introduced paths.
|
||||
|
||||
Potential remediation: retain enough container-shape evidence with stored
|
||||
history events, or select relevant events from existing shape-aware replay
|
||||
evidence. Filter exact definitions and previous origins by the queried semantic
|
||||
shape while retaining genuine ancestor replacement/removal events. Filtering
|
||||
only on the current `Change.Path` is insufficient where construction already
|
||||
replaced concrete segment kinds with parsed tokens. Preserve the intentional
|
||||
one-pointer-per-entry `HistoricalPaths` enumeration and contextual behavior of
|
||||
`ParsePath`; neither public contract needs redesign. Cover both direction changes
|
||||
and compare metadata history with explanation.
|
||||
|
||||
## 4. Diagnostic canonicalization breaks composition claimant ordering
|
||||
|
||||
Priority: P3. Status: resolved. Evidence: `TestFacadeCompositionConflictKeepsClaimantOrder`,
|
||||
the engine diagnostic-order regression, and the integrated checks recorded at
|
||||
`07e4ae5:docs/roadmap/implementation.md`.
|
||||
|
||||
Relevant code: `compositionConflictDiagnostic` in
|
||||
[compose.go](../../internal/engine/compose.go) and `canonicalDiagnostics` in
|
||||
[diagnostic.go](../../internal/engine/diagnostic.go), particularly lines 88–92.
|
||||
The latter runs both while constructing `LoadError` and in `WriteDiagnostics`.
|
||||
|
||||
The [strict-composition contract](../config.md#strict-document-composition)
|
||||
specifies the first claim in scoped assembly order as primary and every remaining
|
||||
claim in the same order as related locations.
|
||||
|
||||
A native-filesystem fixture demonstrates the discrepancy:
|
||||
|
||||
```text
|
||||
main.yml imports a.yml, b.yml, c.yml
|
||||
a.yml imports z.yml
|
||||
b.yml, c.yml, and z.yml each define x
|
||||
```
|
||||
|
||||
Acquisition assigns main=source-1, a=source-2, z=source-3, b=source-4,
|
||||
c=source-5. Dependency-ready assembly considers the three conflicting claims
|
||||
in b, c, z order. The composer correctly chooses b as primary and constructs
|
||||
related locations c, z. Generic canonicalization sorts those related locations
|
||||
by acquisition ID, publishing z, c instead. The reproduced public diagnostic
|
||||
has primary source-4 and related source-3, source-5.
|
||||
|
||||
All claimants remain present and the conflict still fails loading, so this is
|
||||
lower impact than the presence/history defects. It nevertheless violates the
|
||||
documented reporting order and gives consumers two different ordering rules
|
||||
within one conflict report.
|
||||
|
||||
Potential remediation: preserve the selected semantic ordering for composition
|
||||
claimant lists through accumulation and rendering, while retaining canonical
|
||||
ordering of diagnostic records and the established sorting of related locations
|
||||
for diagnostics without a semantic-order contract. Add one public failure-path
|
||||
case whose acquisition and claimant orders differ and verify both structured
|
||||
diagnostics and rendered output. No scheduler or precedence change is needed.
|
||||
@@ -1,186 +0,0 @@
|
||||
# Import Discovery And Facade Boundary Simplification
|
||||
|
||||
Status: target defined; execution is tracked in the [implementation plan](implementation.md).
|
||||
Baseline: `80cf23e7102fca2c5d7c7621e75f930a1ef1ecad`.
|
||||
|
||||
This roadmap brings together the two refactors deferred until after the audit
|
||||
remediation sprint: glob entry preparation (**C03**) and facade-to-engine
|
||||
transport simplification (**F07**). Their original motivation is retained in the
|
||||
[glob](future.md#1-separate-glob-entry-preparation-from-traversal) and
|
||||
[transport](future.md#2-simplify-redundant-facade-to-engine-transport) future-work
|
||||
entries and the [consolidated audit](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md).
|
||||
|
||||
The goal is clearer responsibility and ownership with fewer redundant internal
|
||||
representations. Both changes preserve the public API and configuration model.
|
||||
They are independent work areas within one maintenance effort, not a new loading
|
||||
workflow. The [implementation plan](implementation.md) owns concrete edits,
|
||||
stages, validation commands, and execution progress.
|
||||
|
||||
## Baseline And Targeted End State
|
||||
|
||||
The preceding sprint repaired directory-failure classification and shared link
|
||||
dependency evaluation, clarified acquisition handoffs, and removed unused
|
||||
placement bridges. Those changes provide the baseline; this work does not repeat
|
||||
or redesign them.
|
||||
|
||||
| Area | Current baseline | Target |
|
||||
| --- | --- | --- |
|
||||
| Glob discovery | `selectGlobImportCandidates` interleaves traversal and set operations with substantial per-entry preparation. | The selector coordinates discovery; a cohesive private operation prepares a wildcard-discovered entry. |
|
||||
| Facade transport | Import defaults pass through root conversion, an exported engine transport record, an equivalent private engine record, and repeated snapshots. Placement construction also uses setter-style bridges. | Root-owned public records convert explicitly to one engine defaults representation, with straightforward engine option/input construction and identifiable ownership copies. |
|
||||
|
||||
The [architecture policy](../policy/architecture.md), [configuration
|
||||
contract](../config.md), and public declarations remain authoritative. [ADR
|
||||
0006](../adr/0006-public-facade.md) continues to govern the facade boundary. These
|
||||
refactors do not require a new architectural decision or changes to its accepted
|
||||
decision. The [component overview](../internal/overview.md) and [import
|
||||
internals](../internal/imports.md) own implemented structure.
|
||||
|
||||
## Glob Entry Preparation
|
||||
|
||||
### Target Responsibility Split
|
||||
|
||||
In [glob.go](../../internal/engine/glob.go), the selector continues to own pattern
|
||||
validation, component advancement, literal-segment handling, directory
|
||||
enumeration and its accounting, candidate union and sorting, final target
|
||||
validation, exclusions, and requiredness.
|
||||
|
||||
A private glob-specific preparation operation owns the patterned branch's work
|
||||
for one directory entry: matching and hidden-entry filtering, lexical/access path
|
||||
construction, containment checks, target inspection and discovered-link policy,
|
||||
intermediate-directory eligibility, host/native access-path selection, labels,
|
||||
and candidate construction. Its result distinguishes a selected candidate, an
|
||||
ordinary skip, and a diagnostic. It receives the facts needed for that entry
|
||||
rather than mutating the selector's candidate set or surrounding traversal state.
|
||||
|
||||
Use the existing filesystem access and link-resolution helpers. Directory
|
||||
selection already has `prepareImportDirectoryEntry`; it remains a separate owner
|
||||
because its recursion, matching, absence handling, and traversal state differ.
|
||||
Share a smaller operation only where it actually expresses the same semantics
|
||||
and reduces duplication. No common visitor or discovery strategy is needed for
|
||||
this extraction.
|
||||
|
||||
### Behavior To Preserve
|
||||
|
||||
Preserve the current distinctions and processing order documented by
|
||||
[explicit imports](../config.md#explicit-imports) and exercised by the selection
|
||||
tests:
|
||||
|
||||
- Literal components remain explicit selections; discovery filters apply at
|
||||
their existing wildcard boundaries. Moving matching or hidden filtering after
|
||||
filesystem inspection would change which errors are observable.
|
||||
- Keep lexical candidate identity separate from resolved access identity.
|
||||
Native source identity and relative imports retain namespace spelling; host
|
||||
access retains its existing canonicalization and containment behavior.
|
||||
- Keep discovered-link follow rules, intermediate-directory eligibility,
|
||||
missing-target handling, and structured diagnostic sites/classifications.
|
||||
Do not make glob and directory rules identical as a side effect of extraction.
|
||||
- Preserve deterministic candidate and error order, union/deduplication,
|
||||
directory-entry accounting, and the existing point of source admission.
|
||||
Final selected-file validation remains before exclusions where it is today;
|
||||
exclusions do not hide discovery or resource errors.
|
||||
- Retain the preceding sprint's distinction between missing-on-open directories
|
||||
and failures after opening, along with operation-local completed-link reuse.
|
||||
|
||||
The intended benefit is that a maintainer can understand traversal separately
|
||||
from entry eligibility and identity preparation. This is a readability change;
|
||||
it does not select a different search algorithm or claim a speedup.
|
||||
|
||||
## Facade-To-Engine Transport
|
||||
|
||||
### Target Representations
|
||||
|
||||
The root keeps its public `ImportDefaults`, `PlacementMode`, `Options`, `Input`,
|
||||
and `LayeredOptions` types. Explicit conversions remain appropriate at this
|
||||
boundary; consumers must not acquire engine type identity, fields, or methods.
|
||||
|
||||
Inside the engine, consolidate the equivalent `ImportDefaults` transport and
|
||||
private `importDefaults` records into one presence-aware input-defaults
|
||||
representation. Carry that representation through the ordinary and layered
|
||||
options, normalized request, and acquisition policy instead of translating the
|
||||
same five fields between equivalent engine records.
|
||||
|
||||
Keep `resolvedImportPolicy` distinct: it represents concrete per-declaration
|
||||
choices, including selector-specific rules, rather than another copy of optional
|
||||
load-wide input. Likewise, registration compilation and the normalized loading
|
||||
request have real responsibilities and are not replacement targets.
|
||||
|
||||
Make placement and defaults straightforward to construct on the existing engine
|
||||
option/input records. Remove decorator-style bridges made unnecessary by that
|
||||
construction surface. Exporting fields or types within `internal/engine` where
|
||||
needed by the root converter does not make them part of ConfigKit's supported
|
||||
public API. Keep explicit enum conversion and preserve unknown values until the
|
||||
existing option validation can report them; conversion must not silently choose
|
||||
a default or move validation into facade setters.
|
||||
|
||||
### Ownership And Copying
|
||||
|
||||
Make the actual mutable ownership boundaries identifiable. Public load calls
|
||||
continue to snapshot pointed-to default booleans and the pattern slice before
|
||||
source acquisition, as specified by the [public
|
||||
declaration](../../lifecycle.go). Preserve omitted, explicit false, nil pattern,
|
||||
and non-nil empty pattern as distinct inputs where they are distinct today.
|
||||
|
||||
Review the entire handoff, not just the duplicate type definitions: root
|
||||
conversion in [conversion.go](../../conversion.go), ordinary construction in
|
||||
[lifecycle.go](../../lifecycle.go), layered construction in
|
||||
[layered.go](../../layered.go), engine options and normalization, acquisition
|
||||
policy construction, and declaration resolution in
|
||||
[import_spec.go](../../internal/engine/import_spec.go).
|
||||
|
||||
Remove snapshots that merely recopy already-owned read-only defaults as they
|
||||
cross those private representations. Keep copies needed when establishing
|
||||
independent mutable ownership, including any independently owned resolved
|
||||
policy. The target is explainable ownership and less redundant work, not an exact
|
||||
copy count or removal of copying throughout the library. Shared defaults within
|
||||
one load can be read-only by implementation discipline; this creates no new
|
||||
caller immutability or concurrency requirement.
|
||||
|
||||
Preserve ordinary and layered option preflight before source reads and application
|
||||
hooks, independent declaration overrides, transitive/underlay propagation,
|
||||
selected-overlay behavior, destination normalization, and invalid-enum
|
||||
diagnostics. Keep callback, source, path, secret, and returned-record conversions
|
||||
whose ownership or domain meaning is not redundant transport.
|
||||
|
||||
The intended benefit is fewer concepts, field mappings, and construction paths
|
||||
to maintain. Reduced copying is useful but does not establish an end-to-end
|
||||
performance guarantee.
|
||||
|
||||
## Documentation Ownership
|
||||
|
||||
Internal documentation describes the resulting discovery and transport
|
||||
boundaries once implemented. Public declarations continue to own the existing
|
||||
snapshot and type contracts; this effort selects no new public behavior.
|
||||
The corresponding C03/F07 future-work entries serve as navigation to this
|
||||
roadmap rather than parallel target or progress inventories. Unrelated future
|
||||
candidates remain separate. The implementation plan owns the documentation
|
||||
updates and retirement of replaced private representations and helpers.
|
||||
|
||||
## Validation And Completion
|
||||
|
||||
Follow the [testing policy](../policy/testing.md) and [development
|
||||
guide](../development.md#baseline-validation). Reuse the existing glob selection,
|
||||
directory/link failure, import-default, placement, public facade, and dependency
|
||||
boundary coverage. Add a focused behavioral case only where a concrete
|
||||
extraction or ownership risk lacks protection.
|
||||
|
||||
For discovery, verify literal versus wildcard filters, host/native identity,
|
||||
contained and escaping links, optional absence versus read/close failures,
|
||||
ordering, exclusions, regular-file checks, and existing resource accounting. For
|
||||
transport, verify nil/empty and explicit-false distinctions, mutation of caller
|
||||
default storage after the load snapshot through a supported callback, invalid
|
||||
options before input consumption, both loading APIs, and transitive/underlay
|
||||
defaults. Existing conversion-focused tests may change with private construction;
|
||||
preserve the useful ownership behavior rather than fossilizing a helper's shape.
|
||||
|
||||
Completion requires an easier-to-follow selector, one engine input-defaults
|
||||
representation, fewer redundant mapping/construction sites, justified remaining
|
||||
copies, and preserved public behavior under the relevant checks. Review source
|
||||
and ownership flow as well as passing tests; moving complexity into a helper or
|
||||
renaming a duplicate record alone is insufficient.
|
||||
|
||||
No benchmark campaign, complexity score, allocation threshold, exact filesystem
|
||||
call trace, new resource limit, or additional release gate is required. This work
|
||||
adds no dependencies, caches, background activity, or new consumer controls, and
|
||||
does not reopen other audit findings or deferred performance experiments. Routine
|
||||
helper signatures, names, and file placement belong to the implementation plan;
|
||||
no significant product or architectural decision remains open for this scope.
|
||||
@@ -1,523 +0,0 @@
|
||||
# Implementation Remediation Review Findings
|
||||
|
||||
Current follow-up: the public API cleanup finding (9) is complete.
|
||||
The earlier interface-remediation review and completed findings 1–8 below are
|
||||
retained as historical evidence. The current review's scope and validation are
|
||||
recorded with finding 9.
|
||||
|
||||
Reviewed commit: `98c8b7c8423a816acdfceace36165366b13719ee`.
|
||||
Algorithmic follow-up: `91769e9` (unchanged production code).
|
||||
Comparison baseline: `0dd16aa8a935645ae2847d32edd86461dc4618f0`
|
||||
(the planning commit, before the implementation sprint).
|
||||
|
||||
Scope: the completed implementation plan at
|
||||
`07e4ae5:docs/roadmap/implementation.md` and
|
||||
[interface remediation roadmap](interface-remediation.md). This report records
|
||||
remaining defects and newly introduced scalability problems; it does not change
|
||||
the selected architecture or public contracts. All eight findings are complete;
|
||||
implementation and validation evidence is recorded per finding.
|
||||
|
||||
## Architecture And Review Evidence
|
||||
|
||||
The public root-owned facade still delegates to the synchronous engine. A
|
||||
per-load history builder now normalizes baseline, source, inheritance, typed
|
||||
checkpoint, CLI, and resolution evidence. Metadata and inspection share its
|
||||
frozen model, with separate public projections and detached query results. The
|
||||
resolution callback retains a separate fixed entry-state view. Retained-root
|
||||
admission remains before effective secret lookup and application validation.
|
||||
The old independent metadata history and published inheritance copies are gone.
|
||||
|
||||
The original presence/explicitness corrections and composition claimant-order
|
||||
correction are present. The shared-history migration is substantial, but the
|
||||
findings below prevent treating its behavioral preservation and indexed-query
|
||||
targets as fully satisfied. No additional public restriction, guarantee, or
|
||||
prohibition requiring reversal was identified in the reviewed changes. In
|
||||
particular, private builder lifecycle guards are not new consumer obligations.
|
||||
|
||||
Review combined code/plan inspection, graph-based producer/consumer tracing,
|
||||
existing tests, and disposable public-API probes run against both revisions.
|
||||
The first three findings were reproduced; the remaining five follow from the
|
||||
new loops and index contents, without performance measurements. Probe programs
|
||||
and the baseline checkout were kept outside the repository. Production code and
|
||||
repository tests were not changed during the review.
|
||||
|
||||
The following checks passed with Go 1.26.10 on Linux, using the installed toolchain
|
||||
and cached dependencies:
|
||||
|
||||
```sh
|
||||
GOTOOLCHAIN=local GOTELEMETRY=off GOPROXY=off go test ./... -count=1
|
||||
GOTOOLCHAIN=local GOTELEMETRY=off GOPROXY=off go test -race ./...
|
||||
GOTOOLCHAIN=local GOTELEMETRY=off GOPROXY=off ./scripts/check.sh
|
||||
git diff --check
|
||||
```
|
||||
|
||||
The passing suite does not detect the reproduced regressions. Suggested coverage
|
||||
below targets those gaps rather than adding a general test matrix or new gates.
|
||||
|
||||
The algorithmic follow-up checked normalization, lookup/index construction,
|
||||
selection, replay dispatch, sensitivity preparation, and retained-root traversal.
|
||||
It expanded finding 4 to the inheritance/resolution adapters and added findings
|
||||
7–8. The existing focused engine history, explanation, inheritance, and secret
|
||||
tests passed with `go test ./internal/engine -run 'History|Explain|Inheritance|Secret' -count=1`.
|
||||
No benchmark data was collected. The selected shared model, ordered-ID sorting,
|
||||
net resolution grouping, scratch-state normalization, whole-tree explanation
|
||||
replay, and fixed-point sensitivity closure are not being reconsidered. The
|
||||
deferred contributor-trace and branch-local replay experiments remain separate.
|
||||
|
||||
## 1. Final Dynamic Field Tags Can Be Lost From Redaction
|
||||
|
||||
Priority: P1. Status: complete.
|
||||
|
||||
Completion: final inventory/sensitivity is registered unconditionally before
|
||||
freezing. `TestFinalDynamicTagRedactsEqualValuedResolution` failed before the fix
|
||||
and passes afterward, protecting effective and historical public rendering.
|
||||
Validation: the full ordinary suite and `git diff --check` passed.
|
||||
|
||||
Relevant code: `resolveLoadInput` in
|
||||
[load_result.go](../../internal/engine/load_result.go), lines 56–73;
|
||||
`freezeMetadataHistory` in [metadata.go](../../internal/engine/metadata.go),
|
||||
lines 146–155; and `sensitivityCandidates` in
|
||||
[history_select.go](../../internal/engine/history_select.go), lines 201–253.
|
||||
|
||||
Resolution evidence is observed only when resolution produces snapshots. The
|
||||
final projection is assigned to `model.final` but never unconditionally observed
|
||||
for path/sensitivity facts. Classification now consumes model observations,
|
||||
instead of also traversing the final projection as the baseline did.
|
||||
|
||||
Reproduction through the public API:
|
||||
|
||||
```go
|
||||
type classified struct {
|
||||
Token string `yaml:"token" configkit:"secret"`
|
||||
}
|
||||
type configuration struct {
|
||||
Value any `yaml:"value"`
|
||||
}
|
||||
|
||||
result, err := configkit.Load[configuration](
|
||||
configkit.Bytes("input", []byte("value: {token: AUDIT-CANARY}\n")),
|
||||
configkit.Options[configuration]{
|
||||
Definition: configkit.Definition[configuration]{
|
||||
Resolve: func(c *configuration, _ *configkit.Resolution) error {
|
||||
c.Value = classified{Token: "AUDIT-CANARY"}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
The map-to-struct assignment leaves canonical values unchanged, so the existing
|
||||
net-change audit accepts the load without a recorded normalization. The final
|
||||
projection carries the concrete struct's secret tag, but no snapshot adds that
|
||||
classification to the model. `WriteEffective` and `Explain(Keys("value",
|
||||
"token"))` expose the canary, including historical explanation values. At the
|
||||
baseline they redact it and report `Redacted: true`.
|
||||
|
||||
Expected behavior follows the existing
|
||||
[secret-classification contract](../config.md#secret-classification-and-effective-rendering):
|
||||
concrete dynamic tags and final/historical classification remain effective.
|
||||
The plan also expressly requires observing the final projection. This concerns
|
||||
ordinary tagged configuration, not evidence of resolved credential bytes being
|
||||
stored in history.
|
||||
|
||||
Remediation: register final concrete path and sensitivity facts before freezing
|
||||
and classification, independently of whether resolution recorded a value
|
||||
change. Preserve pointer-conservative historical masking and dependency closure.
|
||||
Do not require extra resolver records or reject equal-valued dynamic type
|
||||
changes as a workaround. Add a public lifecycle regression for this case that
|
||||
checks effective and historical redaction.
|
||||
|
||||
## 2. Intermediate Source Definitions Are Duplicated In Metadata History
|
||||
|
||||
Priority: P2. Status: complete.
|
||||
|
||||
Completion: displaced definitions are omitted only when a preceding operation
|
||||
already introduced that concrete path with the same represented origin.
|
||||
`TestTierHistoryRecordsEachContributionOnce` failed before the fix and passes
|
||||
for both differing and equal-valued tiers. The full ordinary suite and
|
||||
`git diff --check` passed, including the existing shape-change regressions.
|
||||
|
||||
Relevant code: `observeSourceEvidence` in
|
||||
[history_source.go](../../internal/engine/history_source.go), lines 82–117;
|
||||
and previous-origin construction in `selectHistory` in
|
||||
[history_select.go](../../internal/engine/history_select.go), lines 108–117.
|
||||
|
||||
Each overlay record unconditionally registers its displaced definitions. A
|
||||
definition already represented by the preceding replacement operation is
|
||||
therefore emitted again when the next tier displaces it. Selection chains
|
||||
`Previous` through both records. The baseline's `appendInputOriginEvent`
|
||||
suppressed an already represented origin; the new normalization does not apply
|
||||
that rule to displaced definitions.
|
||||
|
||||
Reproduction: load `map[string]any` with two ordered underlays containing
|
||||
`x: low` and `x: mid`, and main input containing `x: high`. Query
|
||||
`Metadata().History(Keys("x"))`.
|
||||
|
||||
- Expected and baseline: three contributions, low → mid → high.
|
||||
- Actual: four contributions, low → mid → mid → high. The second mid record
|
||||
names the same source location as its own previous origin.
|
||||
|
||||
This is not a genuine additional equal-valued write. It is one source
|
||||
contribution registered twice, contrary to the plan's explicit preservation of
|
||||
origin containment and duplicate suppression.
|
||||
|
||||
Remediation: normalize displaced definitions against already represented
|
||||
semantic operations in the shared model. Preserve genuine independent writes,
|
||||
including equal values, and keep key/index shapes distinct. Add a three-tier
|
||||
history regression checking source chronology and previous-origin links.
|
||||
|
||||
## 3. Container Explanations Take The Last Descendant Replacement's Origin
|
||||
|
||||
Priority: P2. Status: complete.
|
||||
|
||||
Completion: explanation uses the model's direct query-scoped contribution when
|
||||
available and reserves operation fallback for paths without that contribution.
|
||||
`TestOverlayExplanationUsesQueryScopedOrigin` failed before the fix and now
|
||||
checks root, enclosing mapping, and leaf locations. The full ordinary suite and
|
||||
`git diff --check` passed, including removed/replaced descendant coverage.
|
||||
|
||||
Relevant code: `historySelectionForApplication` in
|
||||
[explain.go](../../internal/engine/explain.go), lines 183–207; and descendant
|
||||
selection in [history_select.go](../../internal/engine/history_select.go).
|
||||
|
||||
The explanation helper obtains a direct application selection, then overwrites
|
||||
it with every selected replacement linked to that application. For a container
|
||||
query, multiple child replacements can be relevant; the last one supplies the
|
||||
origin for the entire application event, regardless of the query's scope.
|
||||
|
||||
Reproduction: main YAML is:
|
||||
|
||||
```yaml
|
||||
a: base
|
||||
group: {x: X, y: Y}
|
||||
```
|
||||
|
||||
Select an overlay containing:
|
||||
|
||||
```yaml
|
||||
a: overlay
|
||||
group: {x: O}
|
||||
```
|
||||
|
||||
The overlay event in `Explain(Keys("group"))` is attributed to the `O` scalar
|
||||
(line 2, column 12), instead of the contributing mapping (baseline: line 2,
|
||||
column 8). The root explanation also attributes the whole overlay event to
|
||||
that scalar, despite the independent change to `a` (baseline: document root,
|
||||
line 1, column 1). Values are correct; the contribution location is not.
|
||||
|
||||
The roadmap requires retaining source attribution and using common semantic
|
||||
selection, while allowing different record grouping between public projections.
|
||||
It does not authorize replacing enclosing attribution with an arbitrary leaf.
|
||||
|
||||
Remediation: resolve application attribution at the requested semantic scope in
|
||||
the common selection/attribution path. Prefer a valid direct contribution for
|
||||
an enclosing query; retain replacement fallback where it is needed for removed
|
||||
or replaced descendants. Do not restore a second independent explanation
|
||||
attribution system. Cover enclosing root/mapping and precise leaf attribution
|
||||
in one focused overlay regression.
|
||||
|
||||
## 4. History Construction Repeatedly Performs Unindexed Mapping Searches
|
||||
|
||||
Priority: P2. Status: complete.
|
||||
|
||||
Completion: checkpoints, inheritance sides, and resolution before/final states
|
||||
use one immutable document lookup per stable state, rather than scanning broad
|
||||
mappings for every path. Lookups are rebuilt after scratch replay changes.
|
||||
Removed the unused summary contribution list and its searches; the existing
|
||||
test still verifies composite metadata and individual explanation attribution.
|
||||
The full ordinary suite and `git diff --check` passed, including collection,
|
||||
inheritance, resolution shape, and typed-checkpoint cases.
|
||||
|
||||
Relevant code: `observeTypedCheckpoint` in
|
||||
[history_cli.go](../../internal/engine/history_cli.go), lines 38–49;
|
||||
`sourceContributions` in [history_source.go](../../internal/engine/history_source.go),
|
||||
lines 185–218; `observeInheritanceTransfer` and `documentAtInheritancePath` in
|
||||
[history_inheritance.go](../../internal/engine/history_inheritance.go),
|
||||
lines 87–141 and 211–217; `historyConcretePathAt` and its callers in
|
||||
[history_resolution.go](../../internal/engine/history_resolution.go); and the lookup implementation in
|
||||
[document_walk.go](../../internal/engine/document_walk.go).
|
||||
|
||||
For every checkpoint path, construction calls `documentAtPath` on both trees.
|
||||
That helper supplies no lookup index, so each mapping step linearly searches
|
||||
its entries. For a flat mapping with n fields, locating all n children requires
|
||||
Theta(n²) entry comparisons. Both checkpoints run even on ordinary loads with
|
||||
no CLI overrides. Source-summary construction introduces the same pattern:
|
||||
it calls `sourceContributions` for surviving paths, and that helper searches
|
||||
each raw application again without an index.
|
||||
|
||||
The new inheritance adapter similarly enumerates every before/parent/effective
|
||||
path and then calls `documentAtInheritancePath` for each one. That helper falls
|
||||
back to the same unindexed search: one inheritance transfer of a broad n-field
|
||||
mapping incurs Theta(n²) sibling comparisons. Resolution normalization calls
|
||||
`historyConcretePathAt` before and after for each record; its hand-written
|
||||
mapping scan costs O(rn) for r records under an n-field mapping, or Theta(n²)
|
||||
when all n fields are independently recorded. These are the same lookup problem,
|
||||
not separate findings about the selected inheritance or resolution algorithms.
|
||||
|
||||
These are new repeated sibling scans, not the deliberately retained whole-tree
|
||||
explanation replay. Existing document lookup machinery or paired traversal can
|
||||
avoid them. Existing sorting and genuinely repeated producer evidence still
|
||||
have their own costs; no universal linear-time guarantee is implied.
|
||||
|
||||
Remediation: build/reuse phase-local lookups or collect corresponding nodes
|
||||
during shared traversal instead of independently searching a broad mapping
|
||||
for every child or record. Respect scratch-tree mutation boundaries: do not
|
||||
reuse a stale lookup after replacing or editing its indexed state. Concrete
|
||||
resolution paths must still reflect the corresponding before/after containers.
|
||||
Review the summary membership work as well: the new
|
||||
`historySourcePayload.contributions` list is populated and tested but currently
|
||||
has no production reader. Preserve any membership the selected design needs,
|
||||
but avoid computing unused data through repeated searches. Retain behavior
|
||||
coverage; do not add timing thresholds or implementation-specific scan counts.
|
||||
|
||||
## 5. Prefix Indexing Multiplies One Operation By All Its Descendants
|
||||
|
||||
Priority: P2. Status: complete.
|
||||
|
||||
Completion: indexes locate concrete affected paths rather than placing every
|
||||
descendant at the reported ancestor. Exact path buckets drive source-origin
|
||||
containment (with early success); enclosing queries visit only their affected
|
||||
subtree. Logical operations remain payload references, deduplicated once by the
|
||||
common selector. Thus a leaf no longer scans sibling facts of an ancestor
|
||||
replacement. The full ordinary suite and `git diff --check` passed, including
|
||||
parsed key/index sides, removed descendants, inheritance, and enclosing queries.
|
||||
|
||||
Relevant code: `addObservation` in
|
||||
[history_model.go](../../internal/engine/history_model.go), lines 116–139;
|
||||
replacement observation construction in
|
||||
[history_source.go](../../internal/engine/history_source.go), lines 101–116;
|
||||
`sourceOriginRepresentedByOperation` in that file, lines 245–263; and candidate
|
||||
collection in [history_select.go](../../internal/engine/history_select.go),
|
||||
lines 35–53. CLI and resolution effects use the same operation index.
|
||||
|
||||
An ancestor replacement registers before/after facts for every affected
|
||||
descendant, indexing every distinct observation ID at the same reported
|
||||
operation pointer. The prefix index consequently holds O(n) entries for one
|
||||
logical replacement of an n-node subtree, not one indexed operation plus
|
||||
shape-specific affected-path lookup.
|
||||
|
||||
During source normalization, each surviving descendant calls
|
||||
`sourceOriginRepresentedByOperation`. It visits all those ancestor entries and
|
||||
re-resolves the same operation attribution, even after finding a match. One
|
||||
large subtree replacement therefore creates Theta(n²) visits. Later, a single
|
||||
leaf `History` query gathers and sorts all n entries at its enclosing operation
|
||||
before rejecting unrelated affected paths. Querying n such leaves performs
|
||||
O(n² log n) candidate work despite each leaf's short returned history.
|
||||
|
||||
Remediation: distinguish logical operation indexing from exact affected-path
|
||||
and before/after-shape indexing. Visit operation attribution once, then locate
|
||||
the query's relevant shape facts rather than expanding every sibling fact.
|
||||
Preserve parsed-query deduplication, removed descendants, ancestor replacement
|
||||
effects, and enclosing queries. This should implement the selected localized
|
||||
candidate-query design, not replace the existing prefix mechanism wholesale or
|
||||
coarsen semantic identity.
|
||||
|
||||
## 6. Sensitivity Candidate Deduplication Cannot Match Parsed Paths
|
||||
|
||||
Priority: P3. Status: complete.
|
||||
|
||||
Completion: candidate and dependency deduplication uses structural segment
|
||||
equality, including parsed tokens, without conflating explicit keys and indexes.
|
||||
`TestSensitivityCandidatesMergeRepeatedParsedPaths` failed before the fix and
|
||||
now verifies unique semantic/dependency candidates and merged sensitivity facts.
|
||||
The full ordinary suite and `git diff --check` passed.
|
||||
|
||||
Relevant code: `sensitivityCandidates` and `appendDistinctHistoryPath` in
|
||||
[history_select.go](../../internal/engine/history_select.go), especially
|
||||
lines 207–234; and `sameConcreteHistoryPath` in
|
||||
[history_model.go](../../internal/engine/history_model.go), lines 271–294.
|
||||
|
||||
The candidate collector adds a parsed version of every observation's pointer,
|
||||
then uses a concrete-only comparator to deduplicate candidates. That comparator
|
||||
returns false for a parsed segment, including comparison of a non-root parsed
|
||||
path with itself. Repeated observations of one path therefore append repeated
|
||||
parsed candidates instead of merging them. Parsed resolution dependencies have
|
||||
the same problem in `appendDistinctHistoryPath`.
|
||||
|
||||
For k observations of one non-root pointer, the per-pointer candidate list grows
|
||||
with k and insertion repeatedly scans it: Theta(k²) comparisons and unnecessary
|
||||
retained temporary paths/dependency entries. The outer classifier later uses
|
||||
structural equality to suppress duplicate predicate candidates; this finding
|
||||
does not establish repeated public predicate calls or another redaction leak.
|
||||
|
||||
Remediation: use structural path equality that handles parsed segments for
|
||||
candidate/dependency deduplication, while retaining concrete-only comparison
|
||||
where concrete inventory requires it. Preserve distinct parsed, explicit-key,
|
||||
and explicit-index candidates until classification is unioned by pointer.
|
||||
Extend focused candidate/dependency coverage for repeated parsed paths without
|
||||
asserting timing or promising a new public call-count contract.
|
||||
|
||||
## 7. Explanation Dispatch Repeatedly Searches All Selections And Payloads
|
||||
|
||||
Priority: P2. Status: complete.
|
||||
|
||||
Completion: a query-local payload-reference index and application-fallback map
|
||||
are built in one pass over ordered selections. Source/CLI, inheritance, and
|
||||
resolution replay use direct lookups while retaining model chronology and the
|
||||
query-scoped attribution correction. The tier-history regression now also
|
||||
checks explanation contribution order/origins. The full ordinary suite and
|
||||
`git diff --check` passed; no replay algorithm or shared-state lifetime changed.
|
||||
|
||||
Relevant code: `Inspection.Explain`, `historySelectionForPayload`,
|
||||
`historySelectionForApplication`, and `historySelectionForResolutionGroup` in
|
||||
[explain.go](../../internal/engine/explain.go), especially lines 64–71,
|
||||
106–113, and 174–232; and `appendInheritanceExplanation` in
|
||||
[inheritance_explain.go](../../internal/engine/inheritance_explain.go).
|
||||
|
||||
After the model has selected relevant evidence, each source/CLI application
|
||||
linearly searches the selection list, scans the entire phase payload list to
|
||||
find linked replacement records, and searches selections again for each linked
|
||||
record. Inheritance steps and resolution group members also repeatedly search
|
||||
the same selection slice. Payload references already provide stable,
|
||||
comparable keys; these are lookup operations, not semantic comparisons.
|
||||
|
||||
For A applications, P phase payloads, S selections, and R linked replacements,
|
||||
source/CLI dispatch alone costs O(A(P+S) + RS). With m successive underlay tiers
|
||||
each setting the same scalar in a constant-size configuration, A, P, and S all
|
||||
grow with m: this introduces Theta(m²) dispatch work even though the existing
|
||||
value replay and rendered history for that query have O(m) size/work. It is
|
||||
independent of finding 5's candidate expansion and remains after that index is
|
||||
repaired. The inheritance/resolution lookup loops have the corresponding
|
||||
operation-count times selection-count cost.
|
||||
|
||||
Remediation: index the ordered selections by `historyPayloadRef` once per query
|
||||
and index or group replacement-to-application links once, rather than rediscover
|
||||
them for every application. Reuse that lookup for inheritance substeps and
|
||||
original resolution record IDs. Dispatch can then be linear in the selected
|
||||
records and traversed relationships, excluding the deliberately selected sorting,
|
||||
replay, cloning, and rendering costs. Keep replay chronology unchanged and
|
||||
resolve the attribution precedence correctly with finding 3 rather than
|
||||
preserving its last-descendant bug. Use query-local or eagerly frozen indexes;
|
||||
no lazy mutation of published history is needed. Existing explanation owners
|
||||
should protect output equivalence without a timing assertion.
|
||||
|
||||
## 8. Sensitivity Preparation Expands One Dependency List Per Affected Path
|
||||
|
||||
Priority: P2. Status: complete.
|
||||
|
||||
Completion: ordinary dependency lists are expanded once per recorded target/
|
||||
attribution, and dependency candidates once per attribution, without descendant
|
||||
dependency-list copies. Classification supplies already computed inheritance
|
||||
links to candidate preparation, avoiding a second ordinary-edge construction.
|
||||
`TestResolutionSensitivityKeepsLogicalEdgesWithoutSubtreeDuplication` failed
|
||||
before the fix and now verifies the original edges, including a coalesced child
|
||||
record, and sensitivity isolation from unrelated paths. The full ordinary
|
||||
suite, full race suite, everyday check, and `git diff --check` passed. The
|
||||
original public redaction/history probes also now produce the expected results.
|
||||
|
||||
Relevant code: `sensitivityCandidates`, lines 238–247, and
|
||||
`sensitivityDependencies`, lines 272–286, in
|
||||
[history_select.go](../../internal/engine/history_select.go);
|
||||
`observeResolutionEvidence` and `observeResolutionSubtree` in
|
||||
[history_resolution.go](../../internal/engine/history_resolution.go); and
|
||||
`classifySecretPathsWithEvidence` in [secret.go](../../internal/engine/secret.go).
|
||||
|
||||
One original resolution record owns one dependency list, and all its before/
|
||||
after subtree observations share its attribution reference and reported target.
|
||||
Nevertheless, `sensitivityDependencies` resolves and clones that attribution
|
||||
and emits its full dependency list for every observation. For a single recorded
|
||||
normalization of an n-node subtree with d distinct dependencies, this creates
|
||||
Theta(nd) ordinary edges although there are only d logical target/dependency
|
||||
pairs. With n and d growing together, edge materialization alone is quadratic
|
||||
in the O(n+d) underlying evidence. Those duplicates also become separate
|
||||
triggers in the unchanged sensitivity-closure implementation.
|
||||
|
||||
The candidate collector repeats the attribution dependency loop for every
|
||||
affected path and retains a dependency list on each concrete candidate, although
|
||||
its consumer uses those lists to register dependency paths, not distinct
|
||||
descendant-target edges. It also calls `sensitivityDependencies` a second time
|
||||
for inheritance links, rebuilding and discarding the ordinary edge list. These
|
||||
costs remain even if finding 6's parsed-path comparator is corrected.
|
||||
|
||||
Remediation: enumerate ordinary dependencies once per logical recorded target/
|
||||
attribution, or directly from the original resolution payload, and register each
|
||||
required dependency candidate without broadcasting its list to all descendant
|
||||
observations. A single record's edge preparation should require O(n+d) traversal
|
||||
and at most O(d) ordinary edges, apart from path/annotation sizes and unrelated
|
||||
evidence. Avoid rebuilding ordinary edges merely to obtain inheritance links.
|
||||
Preserve original records omitted by explanation grouping, concrete/parsed
|
||||
predicate candidates, dependency order where observable, and existing
|
||||
pointer-conservative propagation. The fixed-point algorithm and inheritance
|
||||
link semantics need not change. Reuse transitive/cyclic sensitivity regressions
|
||||
and add focused coverage for a subtree record with several dependencies; no
|
||||
performance threshold or new public dependency restriction is warranted.
|
||||
|
||||
## 9. Source Lookup Test Compares Canonical Paths With Symlinked Fixture Paths
|
||||
|
||||
Priority: P2. Status: complete. This is a test portability defect, not a production
|
||||
source-lookup defect.
|
||||
|
||||
Completion: `TestResultSourceLookup` canonicalizes its fixture directory with
|
||||
`filepath.EvalSymlinks` before creating files, preserving all source-attribution,
|
||||
redaction, and detachment assertions. The focused test failed with a symlinked
|
||||
temporary root before the fix. Both source-lookup tests now pass with `TMPDIR`
|
||||
pointing to either the real directory or its symlink. The everyday
|
||||
`./scripts/check.sh` also passed. Production code and behavior are unchanged.
|
||||
|
||||
Reviewed revision: `69bd9ead53b0bd1d4b325de2f357b566291a4803`.
|
||||
Comparison baseline: `556b10b2cd32cbe3240ced79f72bfcc2fe1ebc35`.
|
||||
Scope: the completed [API cleanup plan](implementation.md) and
|
||||
[accepted roadmap](api.md), including facade conversions, recording intents,
|
||||
source lookup, observable string migrations, maintained examples, and current
|
||||
documentation. Existing findings 1–8 were not reopened.
|
||||
|
||||
Relevant code: `TestResultSourceLookup` in
|
||||
[source_lookup_test.go](../../source_lookup_test.go), lines 23–26 and 62–74.
|
||||
|
||||
The test identifies imported and underlay sources by comparing `SourceInfo.Path`
|
||||
with the original paths returned by its fixture writer. Host source paths are
|
||||
canonicalized by ConfigKit, but `t.TempDir()` can return a path containing a
|
||||
symlink when the temporary-directory environment names one. The same files then
|
||||
have different lexical path spellings. Both records are present with the correct
|
||||
layers and version evidence, but neither comparison matches, so the test fails
|
||||
with "imported or underlay source evidence missing".
|
||||
|
||||
This is reproducible on Linux with a symlinked `TMPDIR`; it does not depend on
|
||||
access to macOS or establish a new platform-validation gate. The failure-path
|
||||
lookup test in the same file already uses `filepath.EvalSymlinks` for its fixture
|
||||
path and does not have this particular comparison defect.
|
||||
|
||||
Reproduction from the repository root, with disposable files outside the checkout:
|
||||
|
||||
```sh
|
||||
probeRoot=$(mktemp -d /tmp/configkit-source-review.XXXXXX)
|
||||
mkdir "$probeRoot/real"
|
||||
ln -s "$probeRoot/real" "$probeRoot/link"
|
||||
TMPDIR="$probeRoot/link" GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off \
|
||||
go test . -run '^TestResultSourceLookup$' -count=1
|
||||
```
|
||||
|
||||
Expected: the focused test passes for either spelling of a valid temporary
|
||||
directory, retaining its source-evidence assertions. Actual: it fails at line 74
|
||||
with canonical records under the real directory and expected paths under its
|
||||
symlink. The same focused test passes with `TMPDIR` set to the real directory.
|
||||
This false failure can prevent ordinary development/release checks from completing
|
||||
in an otherwise valid environment; it does not indicate lost source evidence.
|
||||
|
||||
Remediation: canonicalize the test's fixture directory before creating its files,
|
||||
or resolve the imported/underlay expected paths with `filepath.EvalSymlinks`, as
|
||||
the failed-load case already does. Preserve record attribution and detachment
|
||||
assertions. Do not change production canonical-path behavior, forbid symlinked
|
||||
temporary directories, or add a platform/CI gate. Verify the existing focused
|
||||
test with both real and symlinked temporary roots after correction.
|
||||
|
||||
Other review results: the root inventory contains the expected 370 exported
|
||||
declarations/members, with exactly the accepted name/signature/value changes
|
||||
against the prior 372-entry catalog. The two fixed recording methods and the
|
||||
existing assignment helpers are the only `addRecord` callers. Source lookup
|
||||
clones retained records using existing ownership/sanitization machinery. No other
|
||||
required architectural gap, production regression, or inadvertently strengthened
|
||||
public contract was identified in this sprint.
|
||||
|
||||
Validation passed on Linux with Go 1.26.10 and cached dependencies:
|
||||
|
||||
```sh
|
||||
GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off ./scripts/check.sh
|
||||
GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test -race ./...
|
||||
GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off \
|
||||
go test . -run 'SourceLookup|ResolutionRecordingIntents|TestPublicFacadeBoundary|TestDependencyImportBoundary|TestLocalDocumentationLinks' -count=1
|
||||
```
|
||||
|
||||
The additional symlink-root invocation above failed as described. Production
|
||||
code and repository tests were not changed during this review.
|
||||
@@ -1,793 +0,0 @@
|
||||
# Public API Catalog And v1.0 Review
|
||||
|
||||
Reviewed revision: `fb71421956ba6b431bdc8745dcf7ab02607dac3a`.
|
||||
Status: discussion draft; no API changes are selected or implemented by this review.
|
||||
|
||||
## Scope And Method
|
||||
|
||||
The supported consumer surface is the root package
|
||||
`gitea.maximumdirect.net/eric/ConfigKit`, package name `configkit`.
|
||||
[ADR 0006](../adr/0006-public-facade.md) owns root type identity and the private
|
||||
implementation boundary. Exported engine names are not consumer API.
|
||||
|
||||
This catalog includes every exported root type, function, method, struct field,
|
||||
and constant in the current build: **372 entries** comprising **54 types,
|
||||
31 functions, 36 methods, 116 fields, and 135 constants**. There are no exported
|
||||
package variables, named interfaces, type aliases, or anonymously embedded public
|
||||
fields. Of the constants, 104 are diagnostic codes: the symbol count does not
|
||||
mean that consumers must learn 372 independent operations.
|
||||
|
||||
Inventory was extracted from the root non-test Go declarations, cross-checked
|
||||
against the package's build-selected files and `go doc -all .`, and reviewed
|
||||
against declaration comments, the [configuration contract](../config.md),
|
||||
[consumer examples](../consumers/README.md), the
|
||||
[architecture policy](../policy/architecture.md), and relevant accepted ADRs.
|
||||
This is an API-design review, not another correctness or performance audit.
|
||||
|
||||
Each catalog row has an assessment addressing clarity, ergonomics, and/or
|
||||
consolidation. **Retain** means no revision is currently warranted, not a new
|
||||
invariant or a promise to preserve private mechanics. **Discuss Dn** identifies
|
||||
a possible pre-v1 naming/removal/signature decision below; **An** is an optional
|
||||
additive idea. Struct declarations show their kind without private fields; all
|
||||
exported fields are separate rows. Callable signatures include generic constraints
|
||||
and receiver types. Constants include their current types and values.
|
||||
|
||||
Go declaration comments and the configuration contract remain the canonical
|
||||
behavior owners. This roadmap is a revision-pinned review record, not a second
|
||||
permanent API reference. Nothing here creates new release gates or consumer
|
||||
requirements. Under the [release policy](../policy/release.md#versioning-and-compatibility),
|
||||
v1 establishes compatibility expectations; it does not prevent later compatible
|
||||
additions. The highest-value decisions now are potential renames/removals that
|
||||
would otherwise require a later incompatible release.
|
||||
|
||||
## Overall Assessment
|
||||
|
||||
The facade has a coherent core: explicit source selection, one complete load,
|
||||
application-owned rules, separate presence/provenance, and safe frozen inspection.
|
||||
Its private implementation can evolve without changing public type ownership.
|
||||
Most of the API should remain. The useful cleanup opportunities are concentrated
|
||||
in vocabulary and small redundant state, not a wholesale loading framework.
|
||||
|
||||
Prioritize D1–D4: these names can encourage an incorrect interpretation of the
|
||||
state a consumer receives. D5–D7 are useful additional naming/signature discussions;
|
||||
D8 is a small surface-hygiene question. A1–A2 can wait unless a concrete consumer
|
||||
need makes them useful now. These are recommendations for discussion, not approved
|
||||
changes or a declaration that v1 must wait for every suggestion.
|
||||
|
||||
## Pre-v1 Discussion Candidates
|
||||
|
||||
### D1. Name the fixed resolution view as entry state
|
||||
|
||||
Affected: `Resolution.InputInfo`; the documentation of `Resolution` and
|
||||
`FieldInfo`.
|
||||
|
||||
The lookup includes retained typed defaults and remains fixed while the resolver
|
||||
changes the working configuration. “Input” can therefore suggest either raw
|
||||
authored values or the mutable current value, neither of which is its complete
|
||||
meaning.
|
||||
|
||||
Recommendation: consider renaming the method to `EntryInfo` and consistently
|
||||
calling this the resolution-entry view. Keep its return type and silent
|
||||
unknown/shape-mismatch result. Keep `IsExplicit` as the convenient surviving-input
|
||||
question with its existing path-validation behavior.
|
||||
|
||||
Alternative: retain `InputInfo`, whose comment already explains the contract,
|
||||
and improve the nearby example. That avoids consumer migration and is defensible
|
||||
if the terminology is already well understood. Do not expose the growing history
|
||||
model through the callback or collapse entry and final metadata to solve a naming
|
||||
problem.
|
||||
|
||||
### D2. Distinguish sensitivity classification from secret references
|
||||
|
||||
Affected: `Definition.Secret`; related terminology around `Secret` and
|
||||
`ValueSnapshot.Redacted`.
|
||||
|
||||
The function marks arbitrary semantic paths sensitive, including ordinary strings
|
||||
and containers. It neither creates nor resolves the typed environment references
|
||||
represented by `Secret`.
|
||||
|
||||
Recommendation: consider `Definition.Sensitive func(Path) bool`. This makes a
|
||||
definition such as `Sensitive: func(path Path) bool { ... }` describe its purpose
|
||||
without implying credential lookup. Preserve the existing tag/predicate union,
|
||||
historical masking, and reference semantics.
|
||||
|
||||
Alternative: keep `Secret` on the field because it aligns with the existing
|
||||
`configkit:"secret"` tag and the established documentation. The current name is
|
||||
not functionally wrong. No tag rename, new classification policy, credential
|
||||
provider, or declassification option follows from this discussion.
|
||||
|
||||
### D3. Make version-policy and version-evidence names literal
|
||||
|
||||
Affected: `SourceVersionModeDefault`, `SourceVersionCheck`, and
|
||||
`SourceInfo.VersionCheck`.
|
||||
|
||||
“Default” describes an implementation/history relationship rather than the
|
||||
selected main-only behavior. A “Check” record can exist for an absent declaration
|
||||
without proving that its checker ran or accepted a value.
|
||||
|
||||
Recommendation: consider `SourceVersionModeMainOnly` for the existing zero mode,
|
||||
`SourceVersionEvidence` for the record, and `SourceInfo.VersionEvidence` for the
|
||||
field. Keep all existing mode values, invocation/absence rules, source-local
|
||||
coordinates, consumption, and redaction behavior. In particular, an if-present
|
||||
mode still has the documented main-absence checker behavior; naming cleanup
|
||||
must not silently change it.
|
||||
|
||||
Alternative: retain the names and make their precise meanings prominent in
|
||||
declaration comments and examples. “Default” is familiar for zero enums, and
|
||||
existing consumers may already understand the evidence qualification. Do not add
|
||||
an “accepted” boolean unless ConfigKit actually chooses to retain that fact under
|
||||
a separately agreed contract.
|
||||
|
||||
### D4. Describe the empty-import-selection subset and remove redundant state
|
||||
|
||||
Affected: `ImportSelection`, `SourceInfo.ImportSelections`,
|
||||
`ImportSelection.Outcome`, `ImportSelectionOutcome`, and `ImportSelectionNone`.
|
||||
|
||||
These records describe optional declarations that selected no source. They are
|
||||
not a complete selection ledger. Their outcome has exactly one supported value,
|
||||
`"none"`; successful acquisition is represented elsewhere by source records.
|
||||
|
||||
Recommendation: consider `EmptyImportSelection` and
|
||||
`SourceInfo.EmptyImportSelections`, retaining path, location, and selector.
|
||||
With that explicit scope, remove the constant-only outcome field/type/constant.
|
||||
This reduces the public model without losing information that these records
|
||||
currently communicate.
|
||||
|
||||
Alternative: retain the broad names and explicit outcome. It leaves room for
|
||||
compatible additional outcomes and avoids migration, but consumers must learn
|
||||
that the collection currently reports empty selections only. Future flexibility
|
||||
alone should not imply an approved complete event-history feature.
|
||||
|
||||
### D5. Describe destination fallback evidence more precisely
|
||||
|
||||
Affected: `SourceInfo.DestinationUnresolved`.
|
||||
|
||||
The destination can be a useful nearest resolved enclosing container. The flag
|
||||
does not mean every aspect of placement is unresolved, and a source's own item
|
||||
container can be an exact destination without publishing its item index here.
|
||||
|
||||
Recommendation: consider `DestinationIsFallback` with the existing meaning.
|
||||
Retain `Destination` and `PlacementMode`; another placement object/state machine
|
||||
is not needed just to clarify this boolean.
|
||||
|
||||
Alternative: retain `DestinationUnresolved` and its detailed comment. It is
|
||||
already specific enough for informed consumers. Neither option adds exact item
|
||||
coordinates, identity tracking, or extra source-location guarantees.
|
||||
|
||||
### D6. Separate manual recording intents from inspection-only operation kinds
|
||||
|
||||
Affected: `Resolution.Record` and its use of `ChangeKind`.
|
||||
|
||||
Four named operation values are exported, but only derived-default and
|
||||
normalization are valid manual recording intents. Decoding and inheritance
|
||||
describe library processing. A caller can choose an apparently suitable exported
|
||||
constant only to receive a load-time invalid-kind diagnostic.
|
||||
|
||||
Recommendation for discussion: consider replacing manual `Record` with
|
||||
`RecordDerivedDefault(path Path, reason string, dependencies ...Path)` and
|
||||
`RecordNormalization(path Path, reason string, dependencies ...Path)` methods.
|
||||
Keep the generic assignment helpers `Default` and `Normalize`, which do different
|
||||
work, and keep all inspection `ChangeKind` values. The explicit methods remove a
|
||||
misleading input choice without changing the two accepted intents.
|
||||
|
||||
Alternative: retain the single method and prominently document its accepted
|
||||
subset. A separate input-only kind type is another viable design, but adds a
|
||||
second enum and conversion vocabulary; it is less attractive unless consumers
|
||||
need to select recording intent dynamically. Do not change net-change auditing
|
||||
or impose new recording obligations through this cleanup.
|
||||
|
||||
### D7. Make environment mutation evident in the bootstrap function name
|
||||
|
||||
Affected: `LoadSecretsDir`.
|
||||
|
||||
Unlike ordinary `Load`, this explicit startup operation writes previously unset
|
||||
process environment variables and can report partial application failure.
|
||||
|
||||
Recommendation: consider `BootstrapSecretsDir`. It follows the repository's
|
||||
existing bootstrap terminology and makes the distinction from configuration
|
||||
loading easier to notice. Retain its report-plus-error return and all current
|
||||
preflight, skip, partial-failure, and ownership behavior.
|
||||
|
||||
Alternative: retain `LoadSecretsDir`, whose comment clearly states the side
|
||||
effects. Avoid a broad new bootstrap options framework or merging this operation
|
||||
into ordinary loading. The purpose is naming clarity, not stronger filesystem
|
||||
or process-transaction guarantees.
|
||||
|
||||
### D8. Resolve the intent of the unproduced options diagnostic code
|
||||
|
||||
Affected: `CodeOptionsUnavailable`.
|
||||
|
||||
The scoped implementation search found its root and engine declarations but no
|
||||
named production producer. That is a reason to ask about its intended role, not
|
||||
evidence that an exported symbol has no consumers.
|
||||
|
||||
Recommendation: establish whether there is an intentional supported/reserved case;
|
||||
remove the constant before v1 if there is none. Do not invent a new failure merely
|
||||
to give it a producer.
|
||||
|
||||
Alternative: retain it as deliberately reserved classification if there is a
|
||||
concrete reason. Document that intent rather than automatically deleting it.
|
||||
The other diagnostic families should not be collapsed just to reduce the count.
|
||||
|
||||
## Optional Additive Ideas
|
||||
|
||||
### A1. Direct source lookup on successful results
|
||||
|
||||
`Resolution.Source(id)` and both `SourceContext(id)` methods accept a source ID,
|
||||
while a final result offers only `Sources()` for source records. A consumer
|
||||
following many origin locations must scan or index that slice itself.
|
||||
|
||||
Consider `Result.Source(id string) (SourceInfo, bool)` with the same detached,
|
||||
passive lookup meaning as the resolution query. Prefer it over a general source
|
||||
registry abstraction if representative consumers repeatedly need this lookup.
|
||||
Keeping only the ordered slice is a viable smaller API for consumers that
|
||||
enumerate once. This is an addition that can follow v1; it need not block the
|
||||
existing API freeze.
|
||||
|
||||
### A2. Path comparison without losing segment meaning
|
||||
|
||||
`Path.String()` is a JSON Pointer spelling, not a complete semantic identity:
|
||||
an explicit numeric mapping key and an index can share it. The public type is
|
||||
opaque and currently non-comparable, so consumers cannot directly compare its
|
||||
segment choices without relying on reflection or private representation.
|
||||
|
||||
If consumers need path comparison, consider an explicitly documented comparison
|
||||
operation. Decide whether it means exact segment representation (including
|
||||
parsed-versus-explicit choice and invalid state), or resolution against a
|
||||
document; those are different operations. Prefer a small exact-representation
|
||||
operation over exposing mutable segments or adding another pattern language.
|
||||
Do not label pointer-string equality semantic equality.
|
||||
|
||||
Alternatively keep Path solely as an opaque query/building value and clarify
|
||||
the limitation in examples. No concrete need currently justifies a public
|
||||
segment-inspection framework. A comparison method can be added compatibly later.
|
||||
|
||||
## Consolidation Assessment
|
||||
|
||||
| Area | Assessment |
|
||||
| --- | --- |
|
||||
| C1: ordinary versus layered loading | Keep two entry points. Ordinary options combine one input's choices with load-wide rules; layered Input owns the former and LayeredOptions the latter. Reusing one options type would introduce ignored/competing fields. Anonymous embedding also makes keyed composite literals less convenient. Existing Definition, ImportDefaults, Input, and Override sharing is useful consolidation already. |
|
||||
| C2: filesystem vocabulary | Keep Filesystem (borrowed identity), FilesystemContext (input roots), and ResourceContext (passive returned access) distinct. FS means different concrete types because the roles differ. Clarify with paired host/native examples, rather than introducing one universal context or changing ownership. |
|
||||
| C3: history versus explanation | Keep Change and ValueChange, Metadata.History and Result.Explain distinct. Metadata has composite/previous attribution; explanation has safe values and decoding/net replay. Their shared private evidence is the correct consolidation boundary. |
|
||||
| C4: semantic path versus sequence selector | Keep Path and SequenceSelector distinct. One describes concrete/contextual queries, the other limited mapping-key wildcard registration. Unifying them would broaden grammar and validation for little current benefit. |
|
||||
| Errors and renderers | Keep LoadError and SecretsError separate because bootstrap can accompany partial external effects. Keep structured diagnostics plus safe rendering. SecretsReport.WriteTo follows io.WriterTo; other renderers need not return byte counts merely for symmetry. |
|
||||
| Presence records | Keep FieldInfo, Version and ValueSnapshot's purpose-specific booleans. A generic optional-value/tri-state framework would add vocabulary without simplifying the application configuration structs. |
|
||||
| Result ownership | Keep caller-owned Config and frozen inspection. A copying accessor would not make arbitrary T language-enforced immutable and would add work; emphasize the established snapshot distinction instead. |
|
||||
|
||||
## Related Consumer Integration Contracts
|
||||
|
||||
The Go symbols are not the entire compatibility commitment. These established
|
||||
integration surfaces also matter to v1, but are defined by their canonical
|
||||
contracts rather than counted as additional exported Go declarations:
|
||||
|
||||
| Surface | Owner and assessment |
|
||||
| --- | --- |
|
||||
| Configuration structs, YAML field tags, standard text codecs, defaults and typed decoding | [Schema binding](../config.md#application-schema-binding), [defaults](../config.md#defaults-and-typed-decoding), and [projection](../config.md#typed-projection-and-ownership). Retain ordinary application types and supported standard codec integration; do not add parser-specific public hooks. |
|
||||
| YAML declarations, composition, imports, overlays and sibling inheritance | [Configuration contract](../config.md) and accepted ADRs linked there. Retain the established coherent language; this review does not propose reserved-key or merge-policy changes. |
|
||||
| Presence, provenance, recorded resolution and validation | [Metadata](../config.md#layered-metadata), [resolution](../config.md#recorded-application-resolution), and [validation](../config.md#semantic-validation). Retain the distinctions that remove consumer bookkeeping; naming discussions do not change these semantics. |
|
||||
| Secret references, classification and explicit environment bootstrap | [Secret references](../config.md#typed-secret-references), [classification](../config.md#secret-classification-and-effective-rendering), and [bootstrap](../config.md#explicit-secrets-directory-bootstrap). D2/D7 concern API vocabulary, not a new credential or security model. |
|
||||
| One-shot completion, resource ownership, safe rendering and comparison | [Completion](../config.md#completion-and-resource-lifetime), [source contexts](../config.md#source-resource-contexts), [explanation](../config.md#historical-value-explanation), and [diffs](../config.md#effective-configuration-diffs). Retain established lifetimes and safe snapshot boundaries rather than adding watching, lazy work or a required result Close operation. |
|
||||
|
||||
## Complete Catalog
|
||||
|
||||
All rows below assess the current declarations, not the proposed replacement
|
||||
names. No proposed symbol is counted in the 372-entry inventory.
|
||||
|
||||
### Loading and application policy
|
||||
|
||||
Declarations: [layered.go](../../layered.go), [lifecycle.go](../../lifecycle.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `Input` | `type Input struct` | Retain a source plus placement/import/access settings; zero Source is invalid, unlike explicit NoSource. |
|
||||
| `Input.Source` | `Source` | Retain the opaque source union; no provider interface or parser node exposure. |
|
||||
| `Input.Destination` | `Path` | Retain the same root-relative placement meaning as ordinary options. |
|
||||
| `Input.PlacementMode` | `PlacementMode` | Retain the same explicit placement enum as ordinary options. |
|
||||
| `Input.Imports` | `bool` | Retain per-input traversal choice; it differs from load-wide declaration defaults. |
|
||||
| `Input.Filesystem` | `*FilesystemContext` | Retain per-input access context, not a global context for unrelated namespaces. |
|
||||
| `Underlay` | `type Underlay struct` | Retain a named strict tier; flattening all inputs would lose the peer-versus-precedence boundary. |
|
||||
| `Underlay.Inputs` | `[]Input` | Retain ordered inputs in one strict group; an empty group remains a no-op. |
|
||||
| `LayeredOptions` | `type LayeredOptions[T any] struct` | Retain separate layered entry-point options; input-level settings already belong to Input (C1). |
|
||||
| `LayeredOptions.Definition` | `Definition[T]` | Retain the same Definition type as ordinary loading. |
|
||||
| `LayeredOptions.SourceVersionMode` | `SourceVersionMode` | Discuss D3's mode name; retain one rule across the load rather than per-source policy switches. |
|
||||
| `LayeredOptions.ImportDefaults` | `ImportDefaults` | Retain the shared type and one load-wide default policy. |
|
||||
| `LayeredOptions.Underlays` | `[]Underlay` | Retain ordered low-to-high strict groups; no separate precedence numbers are needed. |
|
||||
| `LayeredOptions.Overlay` | `string` | Retain the same selected-overlay concept as ordinary loading. |
|
||||
| `LayeredOptions.OverlayFilesystem` | `*FilesystemContext` | Retain its explicit overlay-only purpose; merging it into main input context would change behavior (C1/C2). |
|
||||
| `LayeredOptions.Overrides` | `[]Override` | Retain shared Override records and the same CLI semantics. |
|
||||
| `LoadLayered` | `func LoadLayered[T any](main Input, supplied ...LayeredOptions[T]) (*Result[T], error)` | Retain explicit tiers and independent main input; do not make composition strategy a switch. See consolidation assessment C1. |
|
||||
| `Definition` | `type Definition[T any] struct` | Retain reusable application rules separate from per-load selections; zero disables hooks and uses Go-zero defaults. |
|
||||
| `Definition.Defaults` | `func() T` | Retain a fresh-value factory; zero-value configuration and shared mutable defaults are different concerns. |
|
||||
| `Definition.Resolve` | `func(*T, *Resolution) error` | Retain audited mutation callback and error return; do not move application normalization outside loading. |
|
||||
| `Definition.Validate` | `func(*T, *Validation)` | Retain read-only audited validation despite pointer parameter; a value parameter would not make maps/pointers immutable. |
|
||||
| `Definition.Version` | `*VersionRule` | Retain optional application version policy; nil disables the rule. Do not confuse it with the ConfigKit release version. |
|
||||
| `Definition.Secret` | `func(Path) bool` | Discuss D2: rename the classification predicate to Sensitive, distinguishing it from environment-backed Secret references. |
|
||||
| `Definition.SequenceIdentities` | `[]SequenceIdentity` | Retain authoritative identity registrations; no new per-consumer merge strategy is needed. |
|
||||
| `PlacementMode` | `type PlacementMode uint8` | Retain small explicit enum; zero is mapping placement, not automatic inference. |
|
||||
| `SourceVersionMode` | `type SourceVersionMode uint8` | Discuss D3: the zero behavior deserves a descriptive MainOnly name rather than a historical Default label. |
|
||||
| `ImportDefaults` | `type ImportDefaults struct` | Retain independent tri-state defaults; zero leaves library defaults in effect. Do not replace pointers with false-as-unspecified. |
|
||||
| `ImportDefaults.Required` | `*bool` | Retain *bool: nil is unspecified, false is an explicit optional selection. |
|
||||
| `ImportDefaults.Follow` | `*bool` | Retain *bool: explicit false must override the true library default. |
|
||||
| `ImportDefaults.Hidden` | `*bool` | Retain *bool: explicit false must override the true library default. |
|
||||
| `ImportDefaults.Recursive` | `*bool` | Retain *bool: distinguishes declaration defaulting from an explicit choice. |
|
||||
| `ImportDefaults.Pattern` | `[]string` | Retain nil-versus-empty selection meaning; a new pattern language is unwarranted. |
|
||||
| `Options` | `type Options[T any] struct` | Retain ordinary-load options with input-specific settings; do not consolidate by anonymously embedding another public options struct (C1). |
|
||||
| `Options.Definition` | `Definition[T]` | Retain the shared Definition type; avoids duplicating callback configuration. |
|
||||
| `Options.Destination` | `Path` | Retain literal mapping placement independent of filesystem paths; root is the zero Path. |
|
||||
| `Options.PlacementMode` | `PlacementMode` | Retain explicit mapping/item choice; avoid inferring it from destination spelling. |
|
||||
| `Options.Imports` | `bool` | Retain explicit opt-in; import defaults alone must not enable traversal. |
|
||||
| `Options.ImportDefaults` | `ImportDefaults` | Retain one shared load-wide default type, not duplicate boolean fields here. |
|
||||
| `Options.Overlay` | `string` | Retain one selected overlay name; empty selects none. |
|
||||
| `Options.Filesystem` | `*FilesystemContext` | Retain context for ordinary source/import/overlay handling; distinguish from the layered overlay-only context (C1/C2). |
|
||||
| `Options.Overrides` | `[]Override` | Retain explicit CLI assignments; do not generalize these into another arbitrary source tier. |
|
||||
| `Options.SourceVersionMode` | `SourceVersionMode` | Discuss D3's zero-mode name; retain load-wide version policy here. |
|
||||
| `FilesystemContext` | `type FilesystemContext struct` | Retain input access scope, distinct from returned ResourceContext. Consider documentation terminology rather than merging lifetimes (C2). |
|
||||
| `FilesystemContext.BaseDir` | `string` | Retain host-absolute versus namespace-relative coordinates; clarify with paired examples (C2). |
|
||||
| `FilesystemContext.Root` | `string` | Retain explicit scope separate from the source-relative base; do not silently strengthen filesystem security policy. |
|
||||
| `FilesystemContext.FS` | `*Filesystem` | Retain *Filesystem identity, not raw fs.FS: nil selects host context and namespace identity matters (C2). |
|
||||
| `Override` | `type Override struct` | Retain parser-neutral explicit CLI input, distinct from defaults and ordinary sources. |
|
||||
| `Override.Path` | `Path` | Retain application-root semantic coordinates. |
|
||||
| `Override.Value` | `any` | Retain built-in neutral values; accepting arbitrary typed objects would add another conversion contract. |
|
||||
| `Override.Flag` | `string` | Retain safe display attribution, not the raw CLI argument or value. |
|
||||
| `Load` | `func Load[T any](source Source, supplied ...Options[T]) (*Result[T], error)` | Retain the source-only call and one typed options record; the optional form avoids a mandatory empty options value or request builder. |
|
||||
|
||||
### Sources and filesystem namespaces
|
||||
|
||||
Declarations: [resource_context.go](../../resource_context.go), [source.go](../../source.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `ResourceContext` | `type ResourceContext struct` | Retain passive post-acquisition resource access distinct from input scope; zero has no filesystem (C2). |
|
||||
| `ResourceContext.FS` | `fs.FS` | Retain borrowed fs.FS. Callers close files they open; a successful load itself needs no Close. |
|
||||
| `ResourceContext.BaseDir` | `string` | Retain slash-relative source base; do not replace it with a host path that excludes embedded filesystems. |
|
||||
| `Source` | `type Source struct` | Retain opaque acquisition descriptions and deferred validation; zero is invalid and NoSource is deliberate absence. |
|
||||
| `Filesystem` | `type Filesystem struct` | Retain a reusable borrowed fs.FS namespace with identity; zero is not a valid namespace. |
|
||||
| `NewFilesystem` | `func NewFilesystem(label string, filesystem fs.FS) Filesystem` | Retain label plus borrowed fs.FS, returning a namespace whose argument failures surface during load. |
|
||||
| `Filesystem.File` | `func (f Filesystem) File(name string) Source` | Retain native namespace file selection as a method; replacing it with a raw fs.FS Source overload would lose identity/context. |
|
||||
| `File` | `func File(path string) Source` | Retain the short reusable host-file constructor. |
|
||||
| `Bytes` | `func Bytes(label string, data []byte) Source` | Retain immediate byte ownership snapshot and a safe label; delayed constructor diagnostics match other sources. |
|
||||
| `Reader` | `func Reader(label string, input io.Reader) Source` | Retain explicit single-use borrowed-reader semantics; do not add automatic Close or hidden buffering for reuse. |
|
||||
| `Mapping` | `func Mapping(label string, values map[string]any) Source` | Retain immediate neutral-map snapshot; nil root is invalid and empty mapping is meaningful. |
|
||||
| `NoSource` | `func NoSource() Source` | Retain explicit absence separate from zero Source and an empty document. |
|
||||
|
||||
### Explicit main-file discovery
|
||||
|
||||
Declarations: [discovery.go](../../discovery.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `Search` | `type Search struct` | Retain immutable explicit host-search description; zero contributes no candidates. No independent discovery/execution stage is needed. |
|
||||
| `FilenameGroup` | `type FilenameGroup struct` | Retain a small opaque description; zero contributes no names. It is not a general glob matcher. |
|
||||
| `SearchOptions` | `type SearchOptions struct` | Retain whole-search absence policy separate from per-directory filename choices. |
|
||||
| `SearchOptions.Required` | `bool` | Retain optional-by-default search exhaustion; selected-file errors remain terminal. |
|
||||
| `DirectorySearchOptions` | `type DirectorySearchOptions struct` | Retain the filename-group option record; preserve nil/default versus empty/no-candidates distinction. |
|
||||
| `DirectorySearchOptions.Filenames` | `[]FilenameGroup` | Retain ordered groups; no candidate list or candidate-attempt history is necessary. |
|
||||
| `NamedFilenames` | `func NamedFilenames() FilenameGroup` | Retain application-named YAML filename preset; it keeps common consumer setup short. |
|
||||
| `GenericFilenames` | `func GenericFilenames() FilenameGroup` | Retain generic YAML filename preset; separate selection avoids implicit convention changes. |
|
||||
| `CustomFilenames` | `func CustomFilenames(names ...string) FilenameGroup` | Retain explicit filename components and order, not a second glob/template mechanism. |
|
||||
| `SearchDirectory` | `func SearchDirectory(directory string, supplied ...DirectorySearchOptions) Search` | Retain directory search plus optional filenames; argument problems remain load-time diagnostics. |
|
||||
| `Paths` | `func Paths(paths ...string) Search` | Retain literal host-candidate description. Document that this is discovery, not semantic Path construction. |
|
||||
| `Searches` | `func Searches(searches ...Search) Search` | Retain ordered concatenation; it expresses one search, not repeated loads or fallback after parse failure. |
|
||||
| `UnixSystemDirectories` | `func UnixSystemDirectories() Search` | Retain explicit platform preset; do not turn its presence into implicit cross-platform guarantees. |
|
||||
| `UserConfigDirectory` | `func UserConfigDirectory() Search` | Retain explicit OS user-config location preset. |
|
||||
| `HomeDirectory` | `func HomeDirectory() Search` | Retain explicit home-root search preset, distinct from user-config location. |
|
||||
| `WorkingDirectory` | `func WorkingDirectory() Search` | Retain explicit working-directory preset; do not activate it automatically. |
|
||||
| `SearchConfig` | `func SearchConfig(application string, search Search, supplied ...SearchOptions) Source` | Retain deferred source selection inside loading. Optional exhaustion and selected-file failure are intentionally different. |
|
||||
|
||||
### Paths and sequence identity registration
|
||||
|
||||
Declarations: [path.go](../../path.go), [sequence_identity.go](../../sequence_identity.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `Path` | `type Path struct` | Discuss A2: preserve opaque semantic paths; consider exact segment comparison only if consumers need it. Zero is root; current type is not comparable. |
|
||||
| `Keys` | `func Keys(keys ...string) Path` | Retain concise literal-key construction and zero-argument root; do not interpret numeric keys as indexes. |
|
||||
| `ParsePath` | `func ParsePath(pointer string) (Path, error)` | Retain contextual numeric tokens and an error return; pointer spelling alone is not full semantic identity (A2). |
|
||||
| `Path.Key` | `func (p Path) Key(key string) Path` | Retain immutable literal-key append, including empty and numeric keys. |
|
||||
| `Path.Index` | `func (p Path) Index(index int) Path` | Retain explicit sequence indexing; negative indexes produce an invalid path rejected by configuration operations. |
|
||||
| `Path.String` | `func (p Path) String() string` | Retain canonical JSON Pointer formatting, but explicitly avoid calling it a complete semantic identity (A2). |
|
||||
| `SequenceSelector` | `type SequenceSelector []SequenceSelectorSegment` | Retain the named slice of literal/wildcard mapping-key segments; zero selects root. Do not merge it with general Path syntax (C4). |
|
||||
| `SequenceSelectorSegment` | `type SequenceSelectorSegment struct` | Retain the opaque segment; zero is the literal empty key, not a wildcard. |
|
||||
| `SequenceLiteralKey` | `func SequenceLiteralKey(key string) SequenceSelectorSegment` | Retain explicit literal construction, including '*' as a real key. |
|
||||
| `SequenceAnyMappingKey` | `func SequenceAnyMappingKey() SequenceSelectorSegment` | Retain an explicit wildcard constructor; textual '*' must not acquire a second meaning. |
|
||||
| `SequenceIdentity` | `type SequenceIdentity struct` | Retain immutable registration value, not a pluggable merge strategy. Zero lacks required identity fields and is rejected during load. |
|
||||
| `SequenceIdentityAt` | `func SequenceIdentityAt(path Path, fields ...string) SequenceIdentity` | Retain the exact-path convenience; it avoids building a selector for ordinary static destinations. |
|
||||
| `SequenceIdentityMatching` | `func SequenceIdentityMatching(selector SequenceSelector, fields ...string) SequenceIdentity` | Retain wildcard mapping destinations for repeated namespaces; constructor copies inputs. |
|
||||
|
||||
### Resolution, validation, and application schema versions
|
||||
|
||||
Declarations: [lifecycle.go](../../lifecycle.go), [resource_context.go](../../resource_context.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `Resolution` | `type Resolution struct` | Retain a library-issued callback capability; nil/zero/closed contexts are invalid and panic. Do not add a general resolver service interface. |
|
||||
| `VersionRule` | `type VersionRule struct` | Retain one application-owned version path/checker. Zero Path means root; a non-nil rule needs a checker. |
|
||||
| `VersionRule.Path` | `Path` | Retain mode-defined effective/source-local coordinates; clarify the distinction in examples, not separate version systems. |
|
||||
| `VersionRule.Check` | `func(Version, *Validation) error` | Retain Version plus diagnostic context and error return; application acceptance remains application-owned. |
|
||||
| `Version` | `type Version struct` | Retain the compact absent/null/text record rather than imposing a semver or numeric version type. |
|
||||
| `Version.Present` | `bool` | Retain: omission cannot be inferred from Text being empty. |
|
||||
| `Version.Null` | `bool` | Retain: an explicit null is different from absence and an empty string. |
|
||||
| `Version.Text` | `string` | Retain exact accepted spelling; do not expose YAML scalar kinds when string/integer equivalence is intentional. |
|
||||
| `Validation` | `type Validation struct` | Retain the callback-only diagnostic capability; no public constructor or reusable context is needed. |
|
||||
| `Resolution.IsExplicit` | `func (r *Resolution) IsExplicit(path Path) bool` | Retain surviving-input presence semantics, including inherited input; document its schema-path diagnostics versus a lookup miss. |
|
||||
| `Resolution.InputInfo` | `func (r *Resolution) InputInfo(path Path) (FieldInfo, bool)` | Discuss D1: EntryInfo more accurately names the fixed pre-resolution view, including defaults. |
|
||||
| `Resolution.Source` | `func (r *Resolution) Source(id string) (SourceInfo, bool)` | Retain direct acquired-source lookup by ID; optional Result parity is A1. |
|
||||
| `Resolution.Record` | `func (r *Resolution) Record(path Path, kind ChangeKind, reason string, dependencies ...Path)` | Discuss D6: its ChangeKind argument admits inspection-only constants that loading rejects; consider intent-specific record methods. |
|
||||
| `Resolution.Error` | `func (r *Resolution) Error(path Path, message string, related ...Path)` | Retain safe diagnostic collection; do not expose raw application errors automatically. |
|
||||
| `Resolution.Warning` | `func (r *Resolution) Warning(path Path, message string, related ...Path)` | Retain warning/error symmetry and related semantic paths. |
|
||||
| `Default` | `func Default[V any](resolution *Resolution, path Path, target *V, value V, reason string, dependencies ...Path)` | Retain the generic typed assignment helper; explicit zero/false/null must suppress absence-based assignment. |
|
||||
| `Normalize` | `func Normalize[V any](resolution *Resolution, path Path, target *V, value V, reason string, dependencies ...Path)` | Retain unconditional typed assignment plus audit intent; not redundant with absence-based Default. |
|
||||
| `Validation.Error` | `func (v *Validation) Error(path Path, message string, related ...Path)` | Retain value-free errors collected at semantic paths, distinct from unwrapping arbitrary callback errors. |
|
||||
| `Validation.Warning` | `func (v *Validation) Warning(path Path, message string, related ...Path)` | Retain matching warning API; no generic severity switch is necessary. |
|
||||
| `Resolution.SourceContext` | `func (r *Resolution) SourceContext(id string) (ResourceContext, bool)` | Retain passive source-context lookup during the callback, with no I/O. |
|
||||
|
||||
### Results, presence, and source/provenance evidence
|
||||
|
||||
Declarations: [inspection.go](../../inspection.go), [lifecycle.go](../../lifecycle.go), [metadata.go](../../metadata.go), [records.go](../../records.go), [resource_context.go](../../resource_context.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `Result.Explain` | `func (r *Result[T]) Explain(path Path) (Explanation, bool)` | Retain structured safe history plus found boolean; query semantics differ from Metadata.History (C3). |
|
||||
| `Result.WriteEffective` | `func (r *Result[T]) WriteEffective(output io.Writer) error` | Retain frozen redacted YAML output and error-only writer convention; nil/zero snapshot or nil writer is an error. |
|
||||
| `Result.WriteExplanation` | `func (r *Result[T]) WriteExplanation(output io.Writer, path Path) error` | Retain human-readable output. Clarify that unknown paths return an error without output; this is not a new behavior. |
|
||||
| `Result` | `type Result[T any] struct` | Retain the successful configuration plus frozen inspection boundary; zero/nil has no usable loaded snapshot. |
|
||||
| `Result.Config` | `T` | Retain caller-owned mutable T. Clarify that later mutation does not update inspection; replacing it with a cloning getter adds cost without immutability. |
|
||||
| `Result.Metadata` | `func (r *Result[T]) Metadata() Metadata` | Retain detached effective/history query access; do not translate Explain output into metadata. |
|
||||
| `Result.Sources` | `func (r *Result[T]) Sources() []SourceInfo` | Retain ordered detached acquisition records; optional direct Source lookup is A1. |
|
||||
| `Result.Diagnostics` | `func (r *Result[T]) Diagnostics() []Diagnostic` | Retain successful-load nonfatal diagnostics, parallel to structured load failures. |
|
||||
| `Metadata` | `type Metadata struct` | Retain opaque detached queries; zero contains no known paths. |
|
||||
| `Metadata.Lookup` | `func (m Metadata) Lookup(path Path) (FieldInfo, bool)` | Retain effective FieldInfo plus found boolean; this handles absence without optional wrappers in application structs. |
|
||||
| `Metadata.IsExplicit` | `func (m Metadata) IsExplicit(path Path) bool` | Retain ergonomic convenience over Lookup; inherited input is explicit and defaults/resolution do not invent presence. |
|
||||
| `Metadata.History` | `func (m Metadata) History(path Path) []Change` | Retain attribution-only history, including removed paths; it intentionally differs from value replay (C3). |
|
||||
| `Metadata.HistoricalPaths` | `func (m Metadata) HistoricalPaths() []Path` | Retain canonical-pointer enumeration, including removed/default/control paths; no extra per-shape enumeration API is justified. |
|
||||
| `Layer` | `type Layer string` | Retain string-valued provenance categories; base/main terminology merits documentation clarity, not an automatic wire-value rename. |
|
||||
| `SourceKind` | `type SourceKind string` | Retain acquisition kind independently of precedence layer. |
|
||||
| `ChangeKind` | `type ChangeKind string` | Discuss D6's recording input; retain all inspection operations and the empty/default definition state. |
|
||||
| `Location` | `type Location struct` | Retain source ID plus optional line/column coordinates; zero coordinates mean unavailable/synthetic. |
|
||||
| `Location.SourceID` | `string` | Retain a load-local acquired-source key, not a host filename. |
|
||||
| `Location.Line` | `int` | Retain line coordinate; zero means unavailable. |
|
||||
| `Location.Column` | `int` | Retain column coordinate; zero means unavailable. |
|
||||
| `SourceInfo` | `type SourceInfo struct` | Retain structured acquisition and placement evidence; simplify misleading evidence names in D3–D5, not source identity. |
|
||||
| `SourceInfo.ID` | `string` | Retain load-local ID independent of physical path or label. |
|
||||
| `SourceInfo.Label` | `string` | Retain safe display label separate from path and stable identity. |
|
||||
| `SourceInfo.Path` | `string` | Retain host-canonical/native-relative location where present; do not imply every source has a path. |
|
||||
| `SourceInfo.Destination` | `Path` | Retain effective mapping/sequence-container placement; it is not always an item's exact value path. |
|
||||
| `SourceInfo.PlacementMode` | `PlacementMode` | Retain explicit placement evidence, independent of acquisition kind. |
|
||||
| `SourceInfo.DestinationUnresolved` | `bool` | Discuss D5: DestinationIsFallback would describe the enclosing-container evidence more precisely. |
|
||||
| `SourceInfo.Layer` | `Layer` | Retain provenance tier independent of acquisition order and source kind. |
|
||||
| `SourceInfo.Kind` | `SourceKind` | Retain acquisition category rather than inferring it from path syntax. |
|
||||
| `SourceInfo.UnderlayIndex` | `int` | Retain one-based original tier position, zero otherwise; do not renumber around empty tiers. |
|
||||
| `SourceInfo.ImportedFrom` | `*Location` | Retain optional declaring location rather than a second parent-source object graph. |
|
||||
| `SourceInfo.VersionCheck` | `*SourceVersionCheck` | Discuss D3: VersionEvidence avoids implying that the checker ran or accepted anything. |
|
||||
| `SourceInfo.ImportSelections` | `[]ImportSelection` | Discuss D4: name the empty-selection-only scope explicitly. |
|
||||
| `ImportSelector` | `type ImportSelector string` | Retain path/directory/glob selector classification; do not combine it with source acquisition kind. |
|
||||
| `ImportSelectionOutcome` | `type ImportSelectionOutcome string` | Discuss D4: this public enum has only one supported outcome and may be redundant in an explicitly empty-selection record. |
|
||||
| `ImportSelection` | `type ImportSelection struct` | Discuss D4: EmptyImportSelection would accurately name the currently reported subset. |
|
||||
| `ImportSelection.Path` | `Path` | Retain declaration-local path if the record is renamed; not the selected source's destination. |
|
||||
| `ImportSelection.Location` | `Location` | Retain declaration mapping/source coordinates. |
|
||||
| `ImportSelection.Selector` | `ImportSelector` | Retain the authored selector kind; empty path, directory, and glob choices differ. |
|
||||
| `ImportSelection.Outcome` | `ImportSelectionOutcome` | Discuss D4: remove the constant-only none field if empty-only scope is made explicit. |
|
||||
| `SourceVersionCheck` | `type SourceVersionCheck struct` | Discuss D3: SourceVersionEvidence better describes observed declaration state without implying validation success. |
|
||||
| `SourceVersionCheck.Path` | `Path` | Retain requested source-local version path, including absent evidence. |
|
||||
| `SourceVersionCheck.Version` | `Version` | Retain absent/null/text observation, not an acceptance result. |
|
||||
| `SourceVersionCheck.Location` | `*Location` | Retain optional actual/nearest authored location. |
|
||||
| `SourceVersionCheck.Redacted` | `bool` | Retain explicit withheld-text indication; absence cannot be inferred from empty Text. |
|
||||
| `InheritanceStep` | `type InheritanceStep struct` | Retain explicit transfer/control provenance; it adds no acquired source or precedence layer. |
|
||||
| `InheritanceStep.From` | `Path` | Retain contributor semantic path. |
|
||||
| `InheritanceStep.To` | `Path` | Retain destination semantic path. |
|
||||
| `InheritanceStep.Reference` | `Path` | Retain controlling extends path, distinct from the inherited value path. |
|
||||
| `InheritanceStep.Locations` | `[]Location` | Retain directive coordinates rather than mislabeling them as value coordinates. |
|
||||
| `Origin` | `type Origin struct` | Retain composite locations, precedence, operation and transfer trace; no generic untyped metadata bag. |
|
||||
| `Origin.Layer` | `Layer` | Retain provenance classification; inheritance does not invent another layer. |
|
||||
| `Origin.Locations` | `[]Location` | Retain ordered composite origins; one SourceID field would lose strict composition evidence. |
|
||||
| `Origin.Operation` | `ChangeKind` | Retain inspection ChangeKind, including decoding/inheritance (D6 concerns recording input only). |
|
||||
| `Origin.Inheritance` | `[]InheritanceStep` | Retain concrete derivation steps separately from acquired source locations. |
|
||||
| `FieldInfo` | `type FieldInfo struct` | Retain compact effective presence/null/origin record. |
|
||||
| `FieldInfo.Explicit` | `bool` | Retain input presence independent of the final Go zero value. |
|
||||
| `FieldInfo.Null` | `bool` | Retain explicit null independently of missing lookup and scalar zero. |
|
||||
| `FieldInfo.Origin` | `Origin` | Retain final effective attribution. |
|
||||
| `Change` | `type Change struct` | Retain attribution-only history and Previous origins; not redundant with ValueChange (C3). |
|
||||
| `Change.Path` | `Path` | Retain reported operation path, which may enclose the queried affected path. |
|
||||
| `Change.Origin` | `Origin` | Retain this definition/operation's attribution. |
|
||||
| `Change.Previous` | `[]Origin` | Retain preceding selected origins after shape filtering. |
|
||||
| `Change.Reasons` | `[]string` | Retain ordered recorded reasons without embedding configuration values. |
|
||||
| `Change.Dependencies` | `[]Path` | Retain original recorded dependency paths independently of replay grouping. |
|
||||
| `Result.SourceContext` | `func (r *Result[T]) SourceContext(id string) (ResourceContext, bool)` | Retain passive lookup by origin source ID; do not open or cache resource files implicitly. |
|
||||
|
||||
### Safe value inspection and comparison
|
||||
|
||||
Declarations: [diff.go](../../diff.go), [inspection.go](../../inspection.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `Difference` | `type Difference struct` | Retain a separate changed-region record; effective comparison is not a provenance/history diff. |
|
||||
| `Difference.Path` | `Path` | Retain canonical changed-region coordinates. |
|
||||
| `Difference.Left` | `ValueSnapshot` | Retain the safe left snapshot under combined classification, not independently rendered context. |
|
||||
| `Difference.Right` | `ValueSnapshot` | Retain left/right symmetry; before/after belongs to chronological history. |
|
||||
| `Difference.HiddenChanged` | `bool` | Retain actual concealed-change indication distinct from Redacted. |
|
||||
| `Diff` | `func Diff[T any](left, right *Result[T]) ([]Difference, error)` | Retain same-type frozen-result comparison; nil/zero results are errors and credential contents are not compared. |
|
||||
| `ValueSnapshot` | `type ValueSnapshot struct` | Retain detached Present/Redacted/YAML state, shared by explanation and diff without exposing parser nodes. |
|
||||
| `ValueSnapshot.Present` | `bool` | Retain absence/deletion versus explicit null; YAML text alone is insufficient. |
|
||||
| `ValueSnapshot.Redacted` | `bool` | Retain a structured mask flag; consumers must not interpret marker text. |
|
||||
| `ValueSnapshot.YAML` | `string` | Retain deterministic safe text, not a reloadable or mutable node promise. |
|
||||
| `ValueChange` | `type ValueChange struct` | Retain value-bearing replay record distinct from metadata Change; do not force both projections into one record (C3). |
|
||||
| `ValueChange.Before` | `ValueSnapshot` | Retain the earlier safe value with explicit presence. |
|
||||
| `ValueChange.After` | `ValueSnapshot` | Retain chronological before/after symmetry. |
|
||||
| `ValueChange.Origin` | `Origin` | Retain attribution from shared evidence, without requiring identical metadata/explanation event lists. |
|
||||
| `ValueChange.Reasons` | `[]string` | Retain ordered application intent; consumers remain responsible for safe prose. |
|
||||
| `ValueChange.Dependencies` | `[]Path` | Retain recorded dependencies and their semantic paths. |
|
||||
| `SecretReferenceInfo` | `type SecretReferenceInfo struct` | Retain explicit resolved-reference annotation; it is different from redaction classification. |
|
||||
| `SecretReferenceInfo.Name` | `string` | Retain public environment name only; do not add credential content. |
|
||||
| `Explanation` | `type Explanation struct` | Retain effective state plus safe chronological values; not a second mutable configuration object. |
|
||||
| `Explanation.Path` | `Path` | Retain the queried semantic path. |
|
||||
| `Explanation.Effective` | `ValueSnapshot` | Retain final safe value even for a path now absent. |
|
||||
| `Explanation.Origin` | `Origin` | Retain effective provenance separate from each historical event's origin. |
|
||||
| `Explanation.History` | `[]ValueChange` | Retain ValueChange replay, not a converted Metadata.History list (C3). |
|
||||
| `Explanation.SecretReference` | `*SecretReferenceInfo` | Retain optional resolved-reference name; a classified path can withhold this annotation. |
|
||||
|
||||
### Typed credentials and explicit bootstrap
|
||||
|
||||
Declarations: [secret.go](../../secret.go), [secrets.go](../../secrets.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `Secret` | `type Secret struct` | Retain opaque environment reference and explicit credential access. Zero is unresolved/unspecified; a surviving non-pointer Secret is required. |
|
||||
| `SecretEnv` | `func SecretEnv(name string) Secret` | Retain an explicit reference constructor; no plain-string credential constructor. |
|
||||
| `Secret.EnvName` | `func (s Secret) EnvName() string` | Retain public reference access separate from credential access. |
|
||||
| `Secret.Value` | `func (s Secret) Value() string` | Retain deliberate credential accessor; empty means unresolved. Do not combine it with formatting. |
|
||||
| `Secret.IsResolved` | `func (s Secret) IsResolved() bool` | Retain cheap explicit resolution-state query despite nonempty-value validation. |
|
||||
| `Secret.Format` | `func (s Secret) Format(state fmt.State, _ rune)` | Retain fmt.Formatter safety for all formatting verbs; do not replace it with only String. |
|
||||
| `Secret.MarshalJSON` | `func (s Secret) MarshalJSON() ([]byte, error)` | Retain name-only json.Marshaler behavior, not a credential serialization API. |
|
||||
| `SecretFileStatus` | `type SecretFileStatus string` | Retain distinct loaded/skipped/not-applied/failed states; partial bootstrap needs more than success/failure. |
|
||||
| `SecretFileResult` | `type SecretFileResult struct` | Retain value-free per-entry bootstrap outcome, distinct from load sources. |
|
||||
| `SecretFileResult.Name` | `string` | Retain entry/environment name, never content. |
|
||||
| `SecretFileResult.Path` | `string` | Retain safe source-file attribution. |
|
||||
| `SecretFileResult.Status` | `SecretFileStatus` | Retain structured status, not interpretation of report text. |
|
||||
| `SecretFileResult.ExistingEmpty` | `bool` | Retain empty-existing winner evidence for skipped entries; zero does not mean that an entry was loaded. |
|
||||
| `SecretsReport` | `type SecretsReport struct` | Retain detached bootstrap outcomes; zero/nil has no entries. A report may accompany an error. |
|
||||
| `SecretsReport.Entries` | `func (r *SecretsReport) Entries() []SecretFileResult` | Retain copied filename-ordered outcomes. |
|
||||
| `SecretsReport.WriteTo` | `func (r *SecretsReport) WriteTo(output io.Writer) (int64, error)` | Retain io.WriterTo-compatible count/error convention; do not force other renderers to return counts just for symmetry. |
|
||||
| `SecretsError` | `type SecretsError struct` | Retain separate bootstrap failure type: reports partial external effects, unlike a failed configuration load. |
|
||||
| `SecretsError.Error` | `func (e *SecretsError) Error() string` | Retain safe value-free summary and errors.As support through its type. |
|
||||
| `SecretsError.Diagnostics` | `func (e *SecretsError) Diagnostics() []Diagnostic` | Retain detached bootstrap diagnostics; no automatic raw filesystem/environment error unwrapping. |
|
||||
| `LoadSecretsDir` | `func LoadSecretsDir(directory string) (*SecretsReport, error)` | Discuss D7: BootstrapSecretsDir makes process-environment mutation clearer than another Load name. |
|
||||
|
||||
### Diagnostics and failed loads
|
||||
|
||||
Declarations: [diagnostic.go](../../diagnostic.go), [records.go](../../records.go).
|
||||
|
||||
| Entry | Declaration/type | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `LoadError` | `type LoadError struct` | Retain a concrete inspectable load error and errors.As workflow; zero/nil renders a safe generic failure. |
|
||||
| `LoadError.Error` | `func (e *LoadError) Error() string` | Retain value-free summary, not detailed raw parser/application errors. |
|
||||
| `LoadError.Diagnostics` | `func (e *LoadError) Diagnostics() []Diagnostic` | Retain detached structured diagnostics; do not add Unwrap that defeats safe error boundaries. |
|
||||
| `LoadError.Sources` | `func (e *LoadError) Sources() []SourceInfo` | Retain acquired-source evidence available before failure. |
|
||||
| `WriteDiagnostics` | `func WriteDiagnostics(output io.Writer, diagnostics []Diagnostic) error` | Retain writer-first safe deterministic rendering; do not promise stable prose beyond established contracts. |
|
||||
| `Severity` | `type Severity string` | Retain the two diagnostic severities; no arbitrary numeric priority surface. |
|
||||
| `Code` | `type Code string` | Retain detailed stable diagnostic codes; collapsing categories would lose useful consumer handling. |
|
||||
| `Diagnostic` | `type Diagnostic struct` | Retain a common safe problem record across loading, hooks, and bootstrap. |
|
||||
| `Diagnostic.Code` | `Code` | Retain stable machine classification rather than matching prose. |
|
||||
| `Diagnostic.Severity` | `Severity` | Retain explicit severity, independent of diagnostic code spelling. |
|
||||
| `Diagnostic.Path` | `Path` | Retain semantic configuration path, not a filesystem location. |
|
||||
| `Diagnostic.Message` | `string` | Retain human-readable safe context; no automatic secret inference or blanket prose-stability guarantee. |
|
||||
| `Diagnostic.Primary` | `*Location` | Retain optional primary source position; synthetic reports may lack one. |
|
||||
| `Diagnostic.Related` | `[]Location` | Retain ordered related locations; do not homogenize semantically meaningful composition claimant order. |
|
||||
|
||||
### Constants and their values
|
||||
|
||||
Each constant is separately listed. Retaining a diagnostic code preserves a
|
||||
machine-readable failure distinction; consumers should not infer new guarantees
|
||||
from a name or assume that the current set can never grow. D8 notes the one
|
||||
unproduced named code identified for discussion. This catalog does not prescribe
|
||||
new diagnostics or merge existing failure categories.
|
||||
|
||||
#### PlacementMode constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `PlacementModeMapping` | `PlacementMode = 0` | Retain explicit mapping default. |
|
||||
| `PlacementModeSequenceItem` | `PlacementMode = 1` | Retain explicit record placement. |
|
||||
|
||||
#### SourceVersionMode constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `SourceVersionModeDefault` | `SourceVersionMode = 0` | Discuss D3: MainOnly names the existing zero behavior more precisely. |
|
||||
| `SourceVersionModeIfPresent` | `SourceVersionMode = 1` | Retain; keep the documented main-absence checker behavior. |
|
||||
| `SourceVersionModeRequired` | `SourceVersionMode = 2` | Retain participating-document requirement and existing NoSource behavior. |
|
||||
|
||||
#### Layer constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `LayerDefault` | `Layer = "default"` | Retain distinct provenance layer. |
|
||||
| `LayerBase` | `Layer = "base"` | Retain established base/main attribution; no automatic wire-value rename. |
|
||||
| `LayerUnderlay` | `Layer = "underlay"` | Retain distinct provenance layer. |
|
||||
| `LayerOverlay` | `Layer = "overlay"` | Retain distinct provenance layer. |
|
||||
| `LayerCLI` | `Layer = "cli"` | Retain distinct provenance layer. |
|
||||
| `LayerResolution` | `Layer = "resolution"` | Retain distinct provenance layer. |
|
||||
|
||||
#### SourceKind constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `SourceKindFile` | `SourceKind = "file"` | Retain distinct acquisition kind, independent of layer. |
|
||||
| `SourceKindFilesystem` | `SourceKind = "filesystem"` | Retain distinct acquisition kind, independent of layer. |
|
||||
| `SourceKindBytes` | `SourceKind = "bytes"` | Retain distinct acquisition kind, independent of layer. |
|
||||
| `SourceKindReader` | `SourceKind = "reader"` | Retain distinct acquisition kind, independent of layer. |
|
||||
| `SourceKindMapping` | `SourceKind = "mapping"` | Retain distinct acquisition kind, independent of layer. |
|
||||
| `SourceKindCLI` | `SourceKind = "cli"` | Retain distinct acquisition kind, independent of layer. |
|
||||
|
||||
#### ChangeKind constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `ChangeDecoding` | `ChangeKind = "decoding"` | Retain inspection value; D6 addresses its misleading availability as a Record argument. |
|
||||
| `ChangeInheritance` | `ChangeKind = "inheritance"` | Retain inspection value; D6 addresses its misleading availability as a Record argument. |
|
||||
| `ChangeDerivedDefault` | `ChangeKind = "derived_default"` | Retain recorded/inspected intent; discuss the Record input shape in D6. |
|
||||
| `ChangeNormalization` | `ChangeKind = "normalization"` | Retain recorded/inspected intent; discuss the Record input shape in D6. |
|
||||
|
||||
#### Severity constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `SeverityError` | `Severity = "error"` | Retain explicit diagnostic severity. |
|
||||
| `SeverityWarning` | `Severity = "warning"` | Retain explicit diagnostic severity. |
|
||||
|
||||
#### Code constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `CodeSourceInvalid` | `Code = "source.invalid"` | Retain distinct source / invalid classification. |
|
||||
| `CodeSourceMissing` | `Code = "source.missing"` | Retain distinct source / missing classification. |
|
||||
| `CodeSourcePermission` | `Code = "source.permission"` | Retain distinct source / permission classification. |
|
||||
| `CodeSourceRead` | `Code = "source.read"` | Retain distinct source / read classification. |
|
||||
| `CodeSourceNotRegular` | `Code = "source.not_regular"` | Retain distinct source / not regular classification. |
|
||||
| `CodeSourceLimitExceeded` | `Code = "source.limit_exceeded"` | Retain distinct source / limit exceeded classification. |
|
||||
| `CodeSourceReaderUsed` | `Code = "source.reader_used"` | Retain distinct source / reader used classification. |
|
||||
| `CodeYAMLInvalid` | `Code = "yaml.invalid"` | Retain distinct yaml / invalid classification. |
|
||||
| `CodeYAMLEmpty` | `Code = "yaml.empty"` | Retain distinct yaml / empty classification. |
|
||||
| `CodeYAMLMultipleDocuments` | `Code = "yaml.multiple_documents"` | Retain distinct yaml / multiple documents classification. |
|
||||
| `CodeYAMLRootType` | `Code = "yaml.root_type"` | Retain distinct yaml / root type classification. |
|
||||
| `CodeYAMLDuplicateKey` | `Code = "yaml.duplicate_key"` | Retain distinct yaml / duplicate key classification. |
|
||||
| `CodeYAMLTag` | `Code = "yaml.tag"` | Retain distinct yaml / tag classification. |
|
||||
| `CodeYAMLAnchor` | `Code = "yaml.anchor"` | Retain distinct yaml / anchor classification. |
|
||||
| `CodeYAMLAlias` | `Code = "yaml.alias"` | Retain distinct yaml / alias classification. |
|
||||
| `CodeYAMLMergeKey` | `Code = "yaml.merge_key"` | Retain distinct yaml / merge key classification. |
|
||||
| `CodeYAMLScalar` | `Code = "yaml.scalar"` | Retain distinct yaml / scalar classification. |
|
||||
| `CodeYAMLDepthLimit` | `Code = "yaml.depth_limit"` | Retain distinct yaml / depth limit classification. |
|
||||
| `CodeYAMLNodeLimit` | `Code = "yaml.node_limit"` | Retain distinct yaml / node limit classification. |
|
||||
| `CodeSchemaRoot` | `Code = "schema.root"` | Retain distinct schema / root classification. |
|
||||
| `CodeSchemaUnsupportedType` | `Code = "schema.unsupported_type"` | Retain distinct schema / unsupported type classification. |
|
||||
| `CodeSchemaAmbiguousField` | `Code = "schema.ambiguous_field"` | Retain distinct schema / ambiguous field classification. |
|
||||
| `CodeSchemaTag` | `Code = "schema.tag"` | Retain distinct schema / tag classification. |
|
||||
| `CodeSchemaTextCodec` | `Code = "schema.text_codec"` | Retain distinct schema / text codec classification. |
|
||||
| `CodeSchemaInline` | `Code = "schema.inline"` | Retain distinct schema / inline classification. |
|
||||
| `CodeSchemaCycle` | `Code = "schema.cycle"` | Retain distinct schema / cycle classification. |
|
||||
| `CodeSchemaProjectionLimit` | `Code = "schema.projection_limit"` | Retain distinct schema / projection limit classification. |
|
||||
| `CodeSchemaCodec` | `Code = "schema.codec"` | Retain distinct schema / codec classification. |
|
||||
| `CodeSchemaNonFinite` | `Code = "schema.non_finite"` | Retain distinct schema / non finite classification. |
|
||||
| `CodeSchemaDynamicType` | `Code = "schema.dynamic_type"` | Retain distinct schema / dynamic type classification. |
|
||||
| `CodeDecodeType` | `Code = "decode.type"` | Retain distinct decode / type classification. |
|
||||
| `CodeDecodeNull` | `Code = "decode.null"` | Retain distinct decode / null classification. |
|
||||
| `CodeDecodeRange` | `Code = "decode.range"` | Retain distinct decode / range classification. |
|
||||
| `CodeDecodeDuration` | `Code = "decode.duration"` | Retain distinct decode / duration classification. |
|
||||
| `CodeDecodeText` | `Code = "decode.text"` | Retain distinct decode / text classification. |
|
||||
| `CodeDecodeUnknownField` | `Code = "decode.unknown_field"` | Retain distinct decode / unknown field classification. |
|
||||
| `CodeDecodeArrayLength` | `Code = "decode.array_length"` | Retain distinct decode / array length classification. |
|
||||
| `CodeOptionsInvalid` | `Code = "options.invalid"` | Retain distinct options / invalid classification. |
|
||||
| `CodeOptionsUnavailable` | `Code = "options.unavailable"` | Discuss D8: confirm intentional reservation or remove the unproduced classification. |
|
||||
| `CodeImportDisabled` | `Code = "import.disabled"` | Retain distinct import / disabled classification. |
|
||||
| `CodeImportInvalid` | `Code = "import.invalid"` | Retain distinct import / invalid classification. |
|
||||
| `CodeImportMissing` | `Code = "import.missing"` | Retain distinct import / missing classification. |
|
||||
| `CodeImportPermission` | `Code = "import.permission"` | Retain distinct import / permission classification. |
|
||||
| `CodeImportRead` | `Code = "import.read"` | Retain distinct import / read classification. |
|
||||
| `CodeImportOutsideRoot` | `Code = "import.outside_root"` | Retain distinct import / outside root classification. |
|
||||
| `CodeImportCycle` | `Code = "import.cycle"` | Retain distinct import / cycle classification. |
|
||||
| `CodeImportRepeated` | `Code = "import.repeated"` | Retain distinct import / repeated classification. |
|
||||
| `CodeImportLimitExceeded` | `Code = "import.limit_exceeded"` | Retain distinct import / limit exceeded classification. |
|
||||
| `CodeImportVersion` | `Code = "import.version"` | Retain distinct import / version classification. |
|
||||
| `CodeSequenceInvalid` | `Code = "sequence.invalid"` | Retain distinct sequence / invalid classification. |
|
||||
| `CodeSequenceConflict` | `Code = "sequence.conflict"` | Retain distinct sequence / conflict classification. |
|
||||
| `CodeUnderlayVersion` | `Code = "underlay.version"` | Retain distinct underlay / version classification. |
|
||||
| `CodeOverlayInvalid` | `Code = "overlay.invalid"` | Retain distinct overlay / invalid classification. |
|
||||
| `CodeOverlayMissing` | `Code = "overlay.missing"` | Retain distinct overlay / missing classification. |
|
||||
| `CodeOverlayOutsideRoot` | `Code = "overlay.outside_root"` | Retain distinct overlay / outside root classification. |
|
||||
| `CodeOverlayRepeated` | `Code = "overlay.repeated"` | Retain distinct overlay / repeated classification. |
|
||||
| `CodeOverlayDirective` | `Code = "overlay.directive"` | Retain distinct overlay / directive classification. |
|
||||
| `CodeOverlayVersion` | `Code = "overlay.version"` | Retain distinct overlay / version classification. |
|
||||
| `CodeOverlayLimitExceeded` | `Code = "overlay.limit_exceeded"` | Retain distinct overlay / limit exceeded classification. |
|
||||
| `CodeComposeInvalid` | `Code = "compose.invalid"` | Retain distinct compose / invalid classification. |
|
||||
| `CodeComposeConflict` | `Code = "compose.conflict"` | Retain distinct compose / conflict classification. |
|
||||
| `CodeVersionType` | `Code = "version.type"` | Retain distinct version / type classification. |
|
||||
| `CodeVersionError` | `Code = "version.error"` | Retain distinct version / error classification. |
|
||||
| `CodeVersionWarning` | `Code = "version.warning"` | Retain distinct version / warning classification. |
|
||||
| `CodeVersionHookFailed` | `Code = "version.hook_failed"` | Retain distinct version / hook failed classification. |
|
||||
| `CodeResolveError` | `Code = "resolve.error"` | Retain distinct resolve / error classification. |
|
||||
| `CodeResolveWarning` | `Code = "resolve.warning"` | Retain distinct resolve / warning classification. |
|
||||
| `CodeResolveHookFailed` | `Code = "resolve.hook_failed"` | Retain distinct resolve / hook failed classification. |
|
||||
| `CodeResolveInvalidPath` | `Code = "resolve.invalid_path"` | Retain distinct resolve / invalid path classification. |
|
||||
| `CodeResolveInvalidKind` | `Code = "resolve.invalid_kind"` | Retain distinct resolve / invalid kind classification. |
|
||||
| `CodeResolveInvalidRecord` | `Code = "resolve.invalid_record"` | Retain distinct resolve / invalid record classification. |
|
||||
| `CodeResolveInvalidTarget` | `Code = "resolve.invalid_target"` | Retain distinct resolve / invalid target classification. |
|
||||
| `CodeResolveInvalidValue` | `Code = "resolve.invalid_value"` | Retain distinct resolve / invalid value classification. |
|
||||
| `CodeResolveUnrecordedChange` | `Code = "resolve.unrecorded_change"` | Retain distinct resolve / unrecorded change classification. |
|
||||
| `CodeValidateError` | `Code = "validate.error"` | Retain distinct validate / error classification. |
|
||||
| `CodeValidateWarning` | `Code = "validate.warning"` | Retain distinct validate / warning classification. |
|
||||
| `CodeValidateInvalidPath` | `Code = "validate.invalid_path"` | Retain distinct validate / invalid path classification. |
|
||||
| `CodeValidateMutation` | `Code = "validate.mutation"` | Retain distinct validate / mutation classification. |
|
||||
| `CodeSecretsInvalidPath` | `Code = "secrets.invalid_path"` | Retain distinct secrets / invalid path classification. |
|
||||
| `CodeSecretsMissing` | `Code = "secrets.missing"` | Retain distinct secrets / missing classification. |
|
||||
| `CodeSecretsPermission` | `Code = "secrets.permission"` | Retain distinct secrets / permission classification. |
|
||||
| `CodeSecretsRead` | `Code = "secrets.read"` | Retain distinct secrets / read classification. |
|
||||
| `CodeSecretsNotRegular` | `Code = "secrets.not_regular"` | Retain distinct secrets / not regular classification. |
|
||||
| `CodeSecretsInvalidName` | `Code = "secrets.invalid_name"` | Retain distinct secrets / invalid name classification. |
|
||||
| `CodeSecretsLimitExceeded` | `Code = "secrets.limit_exceeded"` | Retain distinct secrets / limit exceeded classification. |
|
||||
| `CodeSecretsInvalidValue` | `Code = "secrets.invalid_value"` | Retain distinct secrets / invalid value classification. |
|
||||
| `CodeSecretsApplyFailed` | `Code = "secrets.apply_failed"` | Retain distinct secrets / apply failed classification. |
|
||||
| `CodeSecretRequired` | `Code = "secret.required"` | Retain distinct secret / required classification. |
|
||||
| `CodeSecretInvalidName` | `Code = "secret.invalid_name"` | Retain distinct secret / invalid name classification. |
|
||||
| `CodeSecretUnset` | `Code = "secret.unset"` | Retain distinct secret / unset classification. |
|
||||
| `CodeSecretEmpty` | `Code = "secret.empty"` | Retain distinct secret / empty classification. |
|
||||
| `CodeOverrideInvalidPath` | `Code = "override.invalid_path"` | Retain distinct override / invalid path classification. |
|
||||
| `CodeOverrideInvalidLabel` | `Code = "override.invalid_label"` | Retain distinct override / invalid label classification. |
|
||||
| `CodeOverrideInvalidValue` | `Code = "override.invalid_value"` | Retain distinct override / invalid value classification. |
|
||||
| `CodeOverrideDuplicate` | `Code = "override.duplicate"` | Retain distinct override / duplicate classification. |
|
||||
| `CodeOverrideOverlap` | `Code = "override.overlap"` | Retain distinct override / overlap classification. |
|
||||
| `CodeOverrideDirective` | `Code = "override.directive"` | Retain distinct override / directive classification. |
|
||||
| `CodeOverrideVersion` | `Code = "override.version"` | Retain distinct override / version classification. |
|
||||
| `CodeOverrideLimitExceeded` | `Code = "override.limit_exceeded"` | Retain distinct override / limit exceeded classification. |
|
||||
| `CodeExplainLimitExceeded` | `Code = "explain.limit_exceeded"` | Retain distinct explain / limit exceeded classification. |
|
||||
| `CodeInheritanceInvalid` | `Code = "inheritance.invalid"` | Retain distinct inheritance / invalid classification. |
|
||||
| `CodeInheritanceMissing` | `Code = "inheritance.missing"` | Retain distinct inheritance / missing classification. |
|
||||
| `CodeInheritanceCycle` | `Code = "inheritance.cycle"` | Retain distinct inheritance / cycle classification. |
|
||||
| `CodeInheritanceVersion` | `Code = "inheritance.version"` | Retain distinct inheritance / version classification. |
|
||||
|
||||
#### ImportSelector constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `ImportSelectorPath` | `ImportSelector = "path"` | Retain distinct authored selector kind. |
|
||||
| `ImportSelectorDirectory` | `ImportSelector = "dir"` | Retain distinct authored selector kind. |
|
||||
| `ImportSelectorGlob` | `ImportSelector = "glob"` | Retain distinct authored selector kind. |
|
||||
|
||||
#### ImportSelectionOutcome constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `ImportSelectionNone` | `ImportSelectionOutcome = "none"` | Discuss D4: redundant if the record explicitly describes empty selections only. |
|
||||
|
||||
#### SecretFileStatus constants
|
||||
|
||||
| Entry | Type and value | Assessment |
|
||||
| --- | --- | --- |
|
||||
| `SecretFileLoaded` | `SecretFileStatus = "loaded"` | Retain successful application outcome. |
|
||||
| `SecretFileSkippedExisting` | `SecretFileStatus = "skipped_existing"` | Retain existing-environment winner, including empty winners. |
|
||||
| `SecretFileNotApplied` | `SecretFileStatus = "not_applied"` | Retain planned but unapplied outcome, distinct from a failed entry. |
|
||||
| `SecretFileFailed` | `SecretFileStatus = "failed"` | Retain failed-entry outcome, distinct from unapplied siblings. |
|
||||
|
||||
## Validation And Next Discussion
|
||||
|
||||
The catalog has one row for each of the 372 exported declarations/members
|
||||
found by the syntax inventory. The callable/type/field signatures were read from
|
||||
the declarations rather than reconstructed from the graph. The graph supported
|
||||
navigation and reference checks; its inventory alone was not treated as proof of
|
||||
completeness. Implicit interfaces include error for `*LoadError` and
|
||||
`*SecretsError`, fmt.Stringer for Path, fmt.Formatter and json.Marshaler for Secret,
|
||||
and io.WriterTo for `*SecretsReport`; there are no separate exported interface types.
|
||||
|
||||
Useful existing behavioral owners include the public facade boundary and
|
||||
compatibility tests, callback-context guards, consumer examples, and metadata,
|
||||
secret, explanation, source-version, discovery, and sequence tests linked by the
|
||||
[development guide](../development.md#task-to-test-map). This documentation-only
|
||||
review adds no tests or production changes. Validation completed: the syntax
|
||||
comparison found exactly one catalog row for all 372 entries, with no missing
|
||||
entries. The local documentation-link and public-facade boundary tests passed,
|
||||
as did the whitespace check.
|
||||
|
||||
Next, decide which D1–D8 candidates merit changes. Prepare a scoped roadmap/plan
|
||||
only for accepted decisions and update the declaration comments, contract owners,
|
||||
examples and consumers together during that implementation. Preserve the current
|
||||
loading, presence, composition, callback-lifetime, redaction and ownership contracts
|
||||
unless a separately explicit decision changes one. No release or tagging action
|
||||
is authorized by this review.
|
||||
@@ -1,276 +0,0 @@
|
||||
# Audit Remediation Roadmap
|
||||
|
||||
Status: target accepted; completed execution is recorded in the historical plan
|
||||
at `bb5540b:docs/roadmap/implementation.md`.
|
||||
Prepared: 2026-10-25. Planning baseline: `e1e94ee`.
|
||||
|
||||
This roadmap describes the target state and related work for the 29 entries
|
||||
selected in the [consolidated audit review](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#settled-scope-decisions).
|
||||
It is intended for maintainers reviewing the remediation's scope and architecture.
|
||||
|
||||
## Document Ownership
|
||||
|
||||
- [Archived audit](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md) records finding IDs, original evidence, detailed remedies and
|
||||
acceptance cases, and the settled scope decisions. Its evidence has not been
|
||||
independently reproduced by writing this roadmap.
|
||||
- This document owns the combined target state, work areas, and design intent.
|
||||
Finding IDs below provide traceability without repeating the full audit inventory.
|
||||
- The historical implementation plan at
|
||||
`bb5540b:docs/roadmap/implementation.md` records concrete stages, private
|
||||
implementation choices, edits, validation commands, and completion evidence.
|
||||
|
||||
The [configuration contract](../config.md), public Go declarations, and
|
||||
[architecture policy](../policy/architecture.md) remain the owners of behavior
|
||||
and guarantees. Update their applicable implementation documentation when work
|
||||
lands; this planning document does not redefine their contracts.
|
||||
|
||||
## Current Baseline And Targeted End State
|
||||
|
||||
The existing loading model remains the foundation. Public loading APIs delegate
|
||||
to the shared engine lifecycle; acquisition retains source scopes for composition,
|
||||
then precedence, inheritance, decoding, CLI overrides, application resolution,
|
||||
secret lookup, and validation produce a detached result with inspection metadata.
|
||||
The [component overview](../internal/overview.md) describes the current owners.
|
||||
|
||||
The audits identify failures at particular traversal, lifetime, error, and
|
||||
accounting boundaries, alongside redundant representations and repeated work.
|
||||
The target is to repair those boundaries and simplify their implementation while
|
||||
preserving ConfigKit's public API and configuration model.
|
||||
|
||||
| Current gap | Targeted outcome |
|
||||
| --- | --- |
|
||||
| Recursive descriptors can fail to terminate, failed dynamic builds can leave partial state, and slice aliases can be mistaken for cycles. | Traversal terminates for the reported cases, failed construction leaves reusable state valid, and supported acyclic values remain accepted. |
|
||||
| Callback and owned-root cleanup can be skipped during panic unwinding; directory errors lose their failure phase. | Cleanup follows the lifetime of each owned resource, and selected-directory failures retain the information needed for correct error handling. |
|
||||
| Finite symlink dependencies can be expanded repeatedly. | Completed dependencies are reused within a resolution while active cycles remain detectable. |
|
||||
| Projection reservations and published history can escape existing accounting. | Existing budgets govern the relevant allocations and complete retained document graph. |
|
||||
| Collection-policy work repeatedly scans or copies unrelated state. | Policy preparation, application, and retained evidence have clear ownership, with work localized to affected policy. |
|
||||
| Acquisition has redundant paths and difficult handoffs; several private representations have no production consumer. | Production paths and their tests share the active protocol, with cohesive handoffs and unused representations removed. |
|
||||
| Some lookups repeat full scans, and some tests assert incidental representation or miss meaningful mutations. | Local indexing avoids the identified repeated work, and tests protect observable contracts at useful boundaries. |
|
||||
|
||||
This is a bounded remediation effort, not a redesign of configuration semantics.
|
||||
Correcting erroneous acceptance, rejection, cleanup, or diagnostics in the
|
||||
reported cases restores existing contracts. It does not select new loading APIs,
|
||||
configuration options, limits, background work, or persistent caches.
|
||||
|
||||
## Selected Work
|
||||
|
||||
The following areas account for all 29 selected entries. Detailed examples and
|
||||
acceptance cases remain with their linked audit group.
|
||||
|
||||
### 1. Safe Typed-Value Traversal And Descriptor Reuse
|
||||
|
||||
Selected entries: **A01, A02, A03, A04, A05** in
|
||||
[schema and typed values](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#a-schema-and-typed-values).
|
||||
|
||||
Make pointer-only descriptor traversal terminate in decoding and path resolution,
|
||||
while preserving supported null values and ordinary recursive structures. Make
|
||||
dynamic descriptor construction transactional: a failed build must not leave
|
||||
partial descriptors available to subsequent operations. Staging successful
|
||||
additions or rolling back the complete failed addition set are implementation
|
||||
choices; both must handle recursive references and preserve prior valid entries.
|
||||
|
||||
Correct active-path cycle detection to distinguish finite slice views sharing
|
||||
storage from actual cycles. Keep detachment and nil/empty behavior intact across
|
||||
the callers that share this traversal machinery.
|
||||
|
||||
Enforce existing projection budgets before large container reservations. Include
|
||||
map-key materialization and overflow-safe lower-bound checks in the review; a
|
||||
check after the reservation does not address the reported failure. This work
|
||||
does not introduce a general heap limit or reject large containers independently
|
||||
of existing budgets.
|
||||
|
||||
Dynamic-type eligibility reuse depends on safe descriptor construction and retains
|
||||
completed successful checks within the value operation. Keep failure diagnostics
|
||||
specific to their current path and distinguish completed results from traversal visits.
|
||||
This removes repeated descriptor-graph walks without a cross-load cache.
|
||||
|
||||
### 2. Callback, Filesystem, And Dependency Lifetimes
|
||||
|
||||
Selected entries: **B01, B02** in [callback lifetime](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#b-callback-and-filesystem-lifetime)
|
||||
and **C01, C02** in [filesystem traversal](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#c-import-selection-and-link-resolution).
|
||||
|
||||
Tie callback-context deactivation to the callback invocation with deferred cleanup
|
||||
so it runs on normal return and panic unwinding. Independently give the owned
|
||||
import root a deferred cleanup fallback. Preserve normal close-error handling,
|
||||
caller ownership, and propagation of the original callback panic. Fixing either
|
||||
state lifetime or handle lifetime does not fix the other.
|
||||
|
||||
Preserve the phase of a directory failure. A genuinely absent directory before
|
||||
successful opening remains subject to existing permissiveness rules; a later
|
||||
read or close failure must not be treated as absence. Apply this distinction to
|
||||
both supported directory-reading paths. Strengthen the shared filesystem tests
|
||||
to check each handle's closure and structured, non-disclosing diagnostics,
|
||||
including partial reads and failures masked by another successful directory.
|
||||
Do not change regular-file close-error policy as a side effect.
|
||||
|
||||
Avoid repeatedly expanding completed finite symlink dependencies in both host
|
||||
and native filesystem resolution. Use operation-local memoization of completed
|
||||
targets, or an equivalent dependency evaluation, with keys that respect the
|
||||
resolution namespace. Keep active-path cycle detection separate from completed
|
||||
work. Preserve containment, supported finite reuse, and existing host-path
|
||||
semantics. The fix must work for directory and glob selection without a new
|
||||
arbitrary traversal cap or changed symlink defaults.
|
||||
|
||||
### 3. Retained History And Combination Evidence
|
||||
|
||||
Selected entries: **D01, D02, D03, D04** in
|
||||
[history and retained state](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#d-retained-history-and-unused-evidence).
|
||||
|
||||
Remove the unconsumed override-result pre-CLI copy and the unqueried published
|
||||
structural-input copy. Preserve the separate pre-CLI state used by active replay
|
||||
and the structural input still used before publication for metadata and secret
|
||||
classification. Remove unused combination-evidence members and the work needed
|
||||
solely to produce them, retaining projections, mappings, origins, and snapshots
|
||||
that have active consumers.
|
||||
|
||||
With retained roots clarified, enforce the existing history allowance against
|
||||
the complete graph published through inspection, including replay and inheritance
|
||||
state and publication-created copies. Count shared nodes once by pointer identity;
|
||||
distinct retained copies still consume the allowance. Account for required copies
|
||||
before creating them where practical. Removing an unused tree alone does not
|
||||
resolve the accounting omissions.
|
||||
|
||||
Keep required before/after evidence and existing inspection behavior. Validate
|
||||
the complete publication path with small controlled allowances, including the
|
||||
interaction of CLI, resolution replay, and inheritance, rather than relying only
|
||||
on tests of an isolated counting helper.
|
||||
|
||||
### 4. Collection-Policy Preparation And Application
|
||||
|
||||
Selected entries: **E01, E02, E03** in
|
||||
[collection policy and projection](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#e-collection-processing-and-efficiency).
|
||||
|
||||
Distinguish the existing policy state used for lookup, changes introduced by an
|
||||
incoming tier, and evidence retained by the assembly. Prepare incoming claims and
|
||||
declarations against read-only lower state, then apply the owned changes at the
|
||||
appropriate combination boundary. Avoid copying every unrelated policy for
|
||||
small tiers and scanning all policies for each independent replacement.
|
||||
|
||||
Use a semantic-path index, localized updates, or equivalent bounded lookup to
|
||||
find affected policy. Preserve retirement timing, policy established by the
|
||||
incoming contribution, pending declarations, persistent explicit modes, and
|
||||
nested record ownership. Copying remains appropriate wherever mutable ownership
|
||||
requires it. Removing only one duplicate clone or shortening a function does not
|
||||
address the identified growth patterns.
|
||||
|
||||
Clarify preparation, evidence application, and finalization responsibilities.
|
||||
Share straightforward history-descriptor translation where useful; evaluate
|
||||
shared record-selection logic while keeping overlay and inheritance origin and
|
||||
mode lifetimes distinct. Retain the common sequence-combination owner. This work
|
||||
does not call for a generic merging framework.
|
||||
|
||||
### 5. Active Acquisition Handoffs And Private Cleanup
|
||||
|
||||
Selected entries: **F01, F02, F03, F04, F05, F06** in
|
||||
[acquisition, cleanup, and test quality](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#f-remaining-maintenance-and-test-improvements).
|
||||
|
||||
Remove the test-only eager acquisition mode so acquisition retains scopes through
|
||||
the active production protocol. Tests that need composition should invoke the
|
||||
actual composition boundary explicitly. Retire the parallel test-only import
|
||||
parser and route relevant fixtures through the active directive parser or the
|
||||
appropriate declaration boundary, retaining malformed-input coverage.
|
||||
|
||||
Clarify active acquisition and coordinator handoffs around cohesive tasks:
|
||||
parsed-input directive/version handling, standalone placement, and repeated tier
|
||||
application/projection. Use explicit inputs and results consistent with existing
|
||||
state owners. Extracting helpers that continue to share surrounding mutable state
|
||||
does not establish a clearer handoff. Preserve ordinary/layered differences,
|
||||
overlay and diff behavior, source identity, callback timing, diagnostics, and
|
||||
accounting scopes.
|
||||
|
||||
Remove the disconnected root record-clone family, uncalled engine helpers, and
|
||||
unread private transport/result members identified in the audit. Reconfirm
|
||||
references on the implementation baseline, including function values and relevant
|
||||
build configurations. Preserve live conversion paths and validation side effects;
|
||||
the audit's absence of field reads is not a general rule for deleting state.
|
||||
Replace meaningful ownership coverage through the public boundary before removing
|
||||
tests that only exercise disconnected helpers.
|
||||
|
||||
### 6. Local Lookup Improvements
|
||||
|
||||
Selected entries: **E04, E05** in
|
||||
[collection policy and projection](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#e-collection-processing-and-efficiency)
|
||||
and **F08** in [secret-failure lookup](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#f08-index-secret-failure-location-queries-lazily).
|
||||
|
||||
Reuse a local document lookup or equivalent traversal for tier-history projection
|
||||
instead of rescanning wide mappings for each sequence. Preserve authored
|
||||
coordinates, sparse projections, and evidence ownership.
|
||||
|
||||
Restore compound identity fields using indexed mapping positions and membership
|
||||
checks rather than rescanning child and merged mappings for every field. Preserve
|
||||
child-authored values and locations, mapping order, and detached nodes.
|
||||
|
||||
Build secret-failure location lookup state lazily when failures need it. Preserve
|
||||
all diagnostics, nearest-location fallbacks, and confidentiality; successful
|
||||
loads should not incur an unnecessary index merely to support failure reporting.
|
||||
These changes address specific repeated work and do not promise a measured
|
||||
startup improvement.
|
||||
|
||||
### 7. Tests That Protect The Intended Behavior
|
||||
|
||||
Selected entries: **F09, F10, F11, F12** in
|
||||
[acquisition, cleanup, and test quality](https://gitea.maximumdirect.net/eric/ConfigKit/src/commit/453da684d7c7d3843a5f505f5c468b4c889dc6e2/docs/roadmap/audit.md#f-remaining-maintenance-and-test-improvements),
|
||||
in addition to the regression coverage attached to each reported defect.
|
||||
|
||||
Cover historical-path enumeration through the public API, including removed
|
||||
paths, queryability, ordering, and detached returned slices. Use those assertions
|
||||
to replace private representation checks where they address the same risk.
|
||||
|
||||
Strengthen fuzz detachment checks by mutating existing descendants or in-length
|
||||
elements, so spare capacity cannot hide aliases. Replace exact filesystem stat
|
||||
call sequences with observable candidate ordering and meaningful failure
|
||||
selection, retaining relevant assertions such as not opening excluded inputs.
|
||||
|
||||
Consolidate facade scaffolding around public construction, loading, errors,
|
||||
ownership, and lifecycle behavior. Preserve distinct integration risks and
|
||||
reader-byte snapshot coverage. Existing coverage percentages or a desired test
|
||||
count are not acceptance criteria for this work.
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
The historical implementation plan at `bb5540b:docs/roadmap/implementation.md`
|
||||
defines the sequential, Luna-scoped stages and their dependencies, including
|
||||
coordinated changes to descriptor state, history ownership/accounting, collection
|
||||
policy, acquisition, and replacement public coverage. It also records validation
|
||||
commands and the complete finding-to-stage map. The audit remains the owner of
|
||||
original evidence and detailed acceptance cases.
|
||||
|
||||
## Validation And Completion
|
||||
|
||||
Validation follows the audit's detailed acceptance cases and the
|
||||
[testing policy](../policy/testing.md). For fatal or hanging regressions, use bounded
|
||||
subprocesses; for budget cases, use small controlled limits. For symlink expansion
|
||||
and repeated lookup work, prefer bounded operation evidence and algorithm review
|
||||
over timing thresholds. Use real filesystem fixtures where filesystem semantics
|
||||
matter and narrow fault injection for read/close failures. State platform limits.
|
||||
|
||||
Applicable development checks come from the [development guide](../development.md),
|
||||
including appropriate race coverage for changed ownership and lifetime boundaries.
|
||||
The historical implementation plan owns their execution. Existing audit results
|
||||
are baseline evidence, not validation of the eventual changes. No performance
|
||||
benchmark campaign is required by this roadmap, and no new benchmark results are
|
||||
claimed.
|
||||
|
||||
Completion means all 29 selected findings have implementation and acceptance
|
||||
evidence, the affected public behavior remains consistent with its contracts,
|
||||
and canonical internal documentation describes the resulting owners. The
|
||||
historical implementation plan records execution status without duplicate
|
||||
progress inventories. Retire completed planning records under the normal
|
||||
documentation lifecycle.
|
||||
|
||||
## Scope Boundaries And Decision Status
|
||||
|
||||
All three audit scope questions are settled. No significant architectural or
|
||||
product decision remains open for this roadmap. The historical implementation
|
||||
plan records private design choices and sequencing, subject to the acceptance
|
||||
cases above.
|
||||
If that work exposes a need to change a public contract, bring the specific
|
||||
decision back for review rather than treating it as an implicit part of remediation.
|
||||
|
||||
The glob preparation refactor (C03) and wider facade transport simplification
|
||||
(F07) have since been selected in the
|
||||
[internal-boundary roadmap](internal-boundaries.md). Other deferred features,
|
||||
clone-traversal redesign, and broader performance experiments remain outside
|
||||
this effort. Keep
|
||||
existing ownership boundaries and loading APIs; no ADR or architecture-policy
|
||||
change is proposed by this roadmap.
|
||||
Reference in New Issue
Block a user