Files
promptkit/docs/roadmap/implementation.md

14 KiB

Captured Configuration Comparison Implementation Plan

Implement the feature roadmap in the numbered order below. Each stage is one bounded implementation prompt for a Luna coding agent. The feature roadmap owns the purpose and target contract; this document owns the steps.

Working Instructions

  • Start with the development guide and follow the agent policy. Read the architecture, testing, documentation, and OSS policies for the stages they govern.
  • Preserve ADR 0001: compare captured ConfigKit effective values for explicit inspection. Leave domain execution, configuration validation, and source processing unchanged.
  • Use the released ConfigKit dependency, not a committed local replacement or workspace file. The sibling checkout is a reference, not a build prerequisite.
  • Keep the upstream comparator and existing sensitivity classifier authoritative. Do not add local diff algorithms, masking rules, output limits, reloads, formatters, or execution-equivalence checks in this work.
  • After each stage, review the complete relevant diff, run its checks, and commit the completed unit with a plain-English message. Record actual validation results in the handoff; do not bypass hooks or publish a release.

Current Baseline And Selected Decisions

At planning time, PromptKit uses ConfigKit v0.6.0. The public inspection methods are in configuration_inspection.go; internal/configuration/inspection.go defines their narrow Inspection interface and currently returns the retained *configkit.Result[document] directly. The internal engine stores that interface. Root inspection contract tests live in configuration_inspection_contract_test.go.

Use ConfigKit v0.7.0, whose reviewed commit is 8f3396d6f0cbe03af4f92bb2c1a1c9798171dd52. The public addition is exactly:

func (v ConfigurationInspection) Diff(other ConfigurationInspection) ([]configkit.Difference, error)

The receiver is left/earlier and the argument is right/later. Either zero view returns ErrInvalidConfig and no records. Successful calls forward ConfigKit's records; errors from ConfigKit remain inspectable through ordinary Go error handling. Do not promise a particular nil-versus-empty slice on success or exact error wording. No context parameter or PromptKit-specific difference type is needed.

For the private bridge, retain the existing Inspection interface and add an unexported accessor for the captured *configkit.Result[document]. Implement the interface with a private wrapper around that result. Existing inspection methods can be promoted from an embedded result; the accessor supplies the result to an internal-package comparison function. This keeps the implementation small without runtime type assertions or exposing the configuration type through the facade. This wrapper is an implementation choice, not a new consumer contract.

Stage 1: Adopt ConfigKit v0.7.0

Status: Complete. The selected tag resolves to reviewed commit 8f3396d6f0cbe03af4f92bb2c1a1c9798171dd52; upstream COPYRIGHT and LICENSE are unchanged from v0.6.0. GOTOOLCHAIN=local go test ./..., GOTOOLCHAIN=local go vet ./..., GOTOOLCHAIN=local python3 scripts/check-examples.py, and git diff --check passed.

Scope: dependency and attribution changes only.

  1. Read the upstream v0.7.0 release notes and diff.go, and verify the selected tag's commit and licensing notices against the baseline above.
  2. Update the dependency with go get gitea.maximumdirect.net/eric/ConfigKit@v0.7.0, then go mod tidy. Review go.mod and go.sum; avoid unrelated upgrades, Go-version changes, or local replacements.
  3. Update the ConfigKit entry in docs/oss/attribution.md: selected version and all upstream source, COPYRIGHT, and LICENSE links must use the exact imported commit. Preserve the house format and actual upstream notices.
  4. Run go test ./..., go vet ./..., and python3 scripts/check-examples.py. Investigate regressions rather than weakening existing loading or execution contracts to accommodate them.
  5. Review the dependency/notice diff and run git diff --check before committing.

Completion: PromptKit uses the published v0.7.0 module, current behavior passes existing validation, and attribution matches the selected source revision.

Stage 2: Add The Private Bridge And Public Method

Status: Complete. Added the private captured-result bridge and public ConfigurationInspection.Diff method. External-package tests cover changed and equal values, operand direction, self-comparison, and all zero-view pairs. GOTOOLCHAIN=local go test . ./internal/configuration ./internal/engine and git diff --check passed.

Scope: the small integration path and basic facade tests.

  1. In internal/configuration/inspection.go, add the private wrapper and captured-result accessor described above. Update loaded.Inspection to return the wrapper for a captured result, keeping absent state represented by a nil inspection. Preserve all existing inspection operations.
  2. Add an internal-package Diff(left, right Inspection) function returning ([]configkit.Difference, error). Obtain the captured results through the accessor and call configkit.Diff[document] once. If an internal operand is absent, pass a nil result to ConfigKit so its existing error behavior applies. Do not reload, reconstruct snapshots, or independently compare values.
  3. Add ConfigurationInspection.Diff to the root facade. Check both source interfaces for nil first and return nil, ErrInvalidConfig for a zero view; otherwise delegate to the bridge. Return upstream errors directly unless useful context is needed, in which case wrap with %w.
  4. Add GoDoc for direction, zero-view errors, frozen effective-value scope, and ConfigKit-owned difference semantics. Note that reports can include ordinary application data and are not evidence of equivalent execution behavior.
  5. Add external-package root tests using independent engines with synthetic mapping inputs and an explicitly defined local backend/profile. Verify a model-value change at a known path, reversed operand direction, equal values, self-comparison, and the three zero-view combinations. Use errors.Is for ErrInvalidConfig and len(records) == 0 for successful equality.
  6. Run gofmt on changed Go files and go test . ./internal/configuration ./internal/engine, then git diff --check. Existing inspection tests must continue to pass.

Completion: the public signature works from package promptkit_test, the private result remains inaccessible through the facade, and unchanged inspection methods still behave as before. No runner or domain-package integration is needed.

Stage 3: Verify Result Semantics And Sensitive Changes

Status: Complete. Facade tests cover distinct source labels with equal effective values, absent versus null, atomic sequence changes, paired secret masking, sensitive shape replacement, and mutation of returned records. GOTOOLCHAIN=local go test . ./internal/configuration and git diff --check passed.

Scope: focused facade integration tests, not a second comparator test suite.

  1. Extend the comparison tests with two valid engine configurations whose effective values are equal but whose underlays/source labels differ. Verify an empty diff; history differences must not become value differences.
  2. Use valid JSON-compatible values in a synthetic provider extra_params map to exercise absence versus explicit null, and a changed sequence. Verify the forwarded Present flags and one atomic sequence-region record. Compare semantic values rather than incidental YAML whitespace.
  3. Add a focused sensitivity case using an existing credential-shaped key such as backends.local.extra_params.token. Change its synthetic secret value and a public sibling. Verify that neither operand's secret appears in either snapshot, that redaction information and HiddenChanged survive the bridge, and that the public change remains visible.
  4. Include one valid shape-change case: an extra_params.details mapping with a nested token on one side and a scalar at details on the other. This places the sensitive descendant on only one side and exercises paired protection of the changed region. Use ConfigKit's documented masking and record granularity; do not require public descendants to remain visible in an incompatible shape change or alter secretProviderPath.
  5. Mutate a returned record's snapshot data and any mutable path representation offered by the upstream public API, then compare again. Verify retained state is unaffected without asserting upstream private allocation details.
  6. Run go test . ./internal/configuration and git diff --check; format any changed Go files. Reuse existing fixture helpers where they fit naturally.

Completion: tests protect PromptKit's forwarding, operand pairing, sensitive-data handling, and result ownership. Upstream retains ownership of exhaustive mapping, sequence, sensitivity, and ordering cases.

Stage 4: Verify Frozen State And Concurrent Inspection

Status: Complete. The existing captured-source fixture now compares two views repeatedly after both sources become unreadable, and concurrently runs inspection, comparison, and offline execution against those captured engines. It confirms stable differences without source reads or comparison-triggered model calls. GOTOOLCHAIN=local go test -race . ./internal/configuration ./internal/engine and git diff --check passed.

Scope: lifecycle and concurrency integration tests.

  1. Reuse or extend the existing captured-source inspection fixture and counting injected model client. Construct both engines while their sources are readable; afterward make those sources unreadable or change their contents. Obtain views and compare them repeatedly. Assert the captured differences remain unchanged and comparison causes no additional source reads or model calls. Set any environment values during setup, not concurrent operations.
  2. Exercise several concurrent comparisons on the same pair of views, together with an existing inspection operation. Validate returned semantic results and collect goroutine errors safely. Avoid sleeps, timing-based thresholds, or assertions about exact internal call sequences.
  3. Where useful, extend the existing concurrent inspection/execution fixture to include comparisons alongside offline runs. Reuse its coverage instead of building a duplicate lifecycle harness.
  4. Run go test -race . ./internal/configuration ./internal/engine and git diff --check; format changed Go files.

Completion: the comparison path demonstrably uses captured state and supports concurrent read-only use without involving prompt execution machinery.

Stage 5: Document The Feature And Validate The Integrated Change

Status: Complete. Added the consumer example, comparison GoDoc, and internal bridge documentation; updated the feature roadmap to implemented. v0.13.0 is already published, so its note remains unchanged; include this feature in the next release note. GOTOOLCHAIN=local go test -race ./..., GOTOOLCHAIN=local go vet ./..., GOTOOLCHAIN=local python3 scripts/check-examples.py, affected local and ConfigKit v0.7.0 link-target checks, and git diff --check passed.

Scope: canonical documentation and final verification.

  1. Add a small comparison example to the configuration-inspection section of docs/consumers/pkg-promptkit.md. Show two captured views, error handling, and iteration over returned records. Link to GoDoc and ConfigKit's v0.7.0 comparison guidance for exact semantics rather than duplicating its API.
  2. Explain the private inspection wrapper and comparison bridge in docs/internal/sources.md. Refresh the existing ConfigKit v0.6.0-specific normalization discussion against v0.7.0 without changing message resource origins or execution normalization as part of this feature.
  3. Keep the example and GoDoc explicit about captured configuration equality: external file contents, resolved credential contents, post-load execution preparation, and per-request overrides are not execution-equivalence inputs. Retain the existing caller responsibility for report disclosure.
  4. If the pending v0.13.0 release document is still unpublished and is the chosen release for this work, add a short feature/dependency note with a canonical documentation link. Otherwise leave published notes unchanged and record the feature during the next release preparation. Do not tag, push, or run a publication command in this stage.
  5. Run go test -race ./..., go vet ./..., python3 scripts/check-examples.py, and git diff --check. Check affected local links and upstream links against the selected release's files. Review exported declarations to confirm only the intended method was added.
  6. Review the final diff against every work item in the feature roadmap, confirming comparison/masking are delegated upstream and runtime/domain components do not acquire ConfigKit inspection dependencies. Commit the completed documentation and any required integration corrections.

Completion: the dependency, API, tests, attribution, and canonical documentation are coherent and the full existing suite and maintained examples pass. Report stage commits and actual check results; release publication remains separate.

Open Questions

None. The accepted roadmap and the existing inspection error convention supply the decisions required for these stages.