Files
configkit/docs/roadmap/implementation.md

486 lines
25 KiB
Markdown
Raw Normal View History

2026-10-27 14:55:22 +00:00
# Pre-v1 Public API Cleanup Implementation Plan
2026-10-25 20:52:11 +00:00
Status: in progress; Stages 1–6 are complete and Stages 7–11 are pending.
2026-10-27 14:55:22 +00:00
Baseline: `07e4ae5d9236935389e81b207d4a8f00543fafce`.
2026-10-26 14:24:07 +00:00
Audience: a Luna coding agent executing the stages sequentially.
2026-10-25 20:52:11 +00:00
## Scope And Execution
2026-10-27 14:55:22 +00:00
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.
2026-10-26 14:24:07 +00:00
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
2026-10-27 14:55:22 +00:00
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 |
2026-10-26 14:24:07 +00:00
| --- | --- |
2026-10-27 14:55:22 +00:00
| 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.
2026-10-27 14:55:22 +00:00
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
2026-10-27 15:01:54 +00:00
Status: complete. Implements D3.
2026-10-27 14:55:22 +00:00
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.
2026-10-27 14:55:22 +00:00
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
2026-10-27 15:07:15 +00:00
Status: complete. Implements N6.
2026-10-27 14:55:22 +00:00
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.
2026-10-27 14:55:22 +00:00
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.
2026-10-27 14:55:22 +00:00
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: pending. 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: pending. 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: pending. 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: pending. Covers all accepted changes' documentation and maintained usage.
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.
2026-10-26 15:25:02 +00:00
Validation:
2026-10-27 14:55:22 +00:00
```sh
go test ./examples/consumers -count=1
go test . -run '^Example|TestLocalDocumentationLinks' -count=1
git diff --check
```
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: pending.
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:
2026-10-26 14:24:07 +00:00
```sh
2026-10-27 14:55:22 +00:00
go test . -run 'TestPublicFacadeBoundary|TestDependencyImportBoundary|TestLocalDocumentationLinks' -count=1
./scripts/check.sh
2026-10-26 14:24:07 +00:00
```
2026-10-27 14:55:22 +00:00
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.