# Pre-v1 Public API Cleanup Implementation Plan Status: in progress; Stage 1 is complete and Stages 2–11 are pending. 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: pending. 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: pending. 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: pending. 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: pending. 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: pending. 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: 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. Validation: ```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: ```sh go test . -run 'TestPublicFacadeBoundary|TestDependencyImportBoundary|TestLocalDocumentationLinks' -count=1 ./scripts/check.sh ``` 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.