Files
commandkit/docs/roadmap/implementation.md

56 KiB
Raw Blame History

Shared reporting and PromptKit v0.20.0 implementation plan

Status: implementation in progress; Stages 1–8 complete.

Scope, authority, and execution

Implement the accepted target in the feature roadmap. That document owns operator intent, selected behavior, OD-1 through OD-11, and exclusions. This plan owns the transition, API design choices, stage order, and verification. Read development, the agent policy, and applicable policies before each stage. Use architecture, testing, documentation, OSS, and release for their respective work. The ADRs explain the accepted architecture.

Execute the numbered stages in order. Each stage is sized for one focused Luna implementation prompt. This is one end-to-end sprint: intermediate stages may fail to compile while dependent callers are being converted. Do not introduce compatibility layers or temporary public APIs to keep those stages green. Carry relevant tests and GoDoc with their owning change; defer broad suites until their dependencies exist. Record completed stages and actual validation here, commit completed reviewable units under repository policy, and preserve unrelated work. A stage boundary is not a publication or compatibility boundary.

The inspected baseline is cb7e05284c554f0da170dc17a0e2e3eac2aed0bc. It has core v0.3.0 requirements in both integrations, ckconfig v0.3.0 in ckprompt, PromptKit v0.18.0, and ConfigKit v1.1.0. The feature roadmap records the pinned PromptKit v0.20.0 and ConfigKit v1.1.0 evidence. Use those released sources only. Do not follow unreleased upstream work or change sibling repos.

Use Go 1.27.0 on PATH as described in the release procedure. Preserve the ignored aligned go.work, go.work.sum, and local credentials. Never inspect token contents. Do not commit workspace files, local replacements, or invented checksums. Core retains its Go 1.26.0 consumer minimum; integrations retain 1.27.0. During joint development use the aligned workspace. Stages 24–26 explicitly handle released requirements and independent builds.

Public names below select a concrete design, not existing API. Private file splits and helper names may follow idiomatic implementation needs. If a concrete API adjustment is necessary, preserve the selected behavior, explain the reason, and update dependent stages; do not reopen settled scope or silently add policy. No arbitrary deep-copy, concurrent-dispatch, exact-byte output, transactional writer, or upstream-domain correctness guarantee is added by this plan.

Coverage and checkpoints

Target owner in the feature roadmap Implementing stages
Shared reporting, safe conversion, universal formats, and output inventory 1–4, 7–9, 23
Public CLI JSON and ordered typed bindings 5–6
Released adoption, resource reports, native errors, and smoke evidence 8–9
OD-1 prepared preview and OD-2 controls/input/aliases 10–11, 13
OD-3 namespace defaults and applicability 12
OD-4 metadata discovery and OD-8 focused inspection 14, 17–18
OD-5 detailed diff and OD-10 assertion outcomes 19
OD-6 failure evidence and aggregate validation 14, 18, 20
OD-9 independent comparison and OD-11 overrides 15–16
Maintained consumers and canonical contracts 21–23
OD-7 releases, real dependency alignment, and final validation 24–26

Stage 1: Shared report representation and safe YAML conversion

Complete. JSON normalization and safe YAML conversion are implemented. Focused conversion tests and the root workspace suite (GOTOOLCHAIN=local go test ./... with Go 1.27.0) passed.

Start in the root package beside reporter.go. Add private report normalization using encoding/json: marshal the original report value, then decode with UseNumber into maps, sequences, scalars, null, and json.Number. Honor JSON tags, omissions, and custom serialization once for all core-serialized formats. Keep numeric tokens intact instead of routing them through float64. Strings remain ordinary strings. Unsupported serialization is an observable error; no stringification fallback.

Add public DecodeYAMLReport(io.Reader) (any, error) for one safe inspection YAML document. Use the existing YAML v4 dependency and a private node walk to produce ordinary JSON-compatible values. Preserve scalar types, presence, null/empty distinctions, sequence order, and numeric value. Standard json.Number may retain JSON numeric tokens without imposing Stage 5's CLI number policy. Convert supported YAML numeric notation faithfully; report an unrepresentable value rather than rounding or silently treating it as text. The helper is explicitly for the restricted inspection value model, not a lossless YAML editor. Reject unsupported meanings, such as a non-string mapping key or multiple logical documents, with a conversion error. Do not parse report strings heuristically or read application configuration structs or source files.

Build one private conversion from the normalized representation to YAML nodes, including numeric nodes rather than quoted numeric strings. This representation also feeds JSON and automatic shape selection. No public document tree or new serialization tags.

Verify JSON field/custom-serialization behavior and meaningful scalar, number, presence, empty-container, and redaction preservation with focused core tests. Include large integers and strings resembling numbers or booleans. Tests compare logical values, not YAML quoting or mapping order.

Stage 2: Writer rendering and standard text templates

Complete. Writer rendering and reusable text templates are implemented. Focused rendering tests and the root workspace suite (GOTOOLCHAIN=local go test ./... with Go 1.27.0) passed.

Add these public root-package contracts:

  • Format with FormatText, FormatYAML, and FormatJSON; its zero value means automatic selection for direct writer use.
  • Report{Value any; TextTemplate *template.Template}.
  • ParseTextTemplate(name, source string, funcs template.FuncMap) (*template.Template, error), using standard text/template; nil funcs is valid.
  • RenderReport(io.Writer, Report, Format) error.

Use one implementation for all formats. Follow the feature roadmap's selection table: explicit format first, otherwise a supplied template selects text, otherwise select by the normalized outer shape. Untemplated strings, numbers, booleans, and nonempty string lists use plain text; structured values, empty collections, and null use YAML. Explicit text for that second group uses the same YAML renderer. For scalar text emit a terminating newline; for string lists emit one item per line. Execute templated text as supplied without another formatting pass. Use conventional readable YAML and JSON encoding; whitespace and map order are not additional contracts. An unknown nonzero writer Format returns an error rather than selecting a fallback.

Templates receive the original Go value. Templated text does not marshal JSON first; explicit YAML/JSON does not execute the template. Template preparation, execution, unsupported serialization, and writer errors remain observable, with no renderer fallback on failure. Callers can prepare reusable templates during assembly and attach preparation errors through existing declaration-error APIs. Use normal template functions initially; no helper framework or public template value model. Caller-supplied template objects retain ordinary Go ownership.

Verify all automatic shapes, explicit precedence, original-value template access, JSON-ignored fields in templates, unsupported JSON values, template errors, large-number YAML/JSON fidelity, and short/error writers. Keep expectations semantic except where the selected text behavior itself matters.

Stage 3: Reporter handoff through the existing lifecycle

Complete. Reporter handoff uses the existing delivery lifecycle. Focused reporter tests and the root workspace suite (GOTOOLCHAIN=local go test ./... with Go 1.27.0) passed.

Add (*Reporter).Report(Report) error. Delegate to Stage 2 through the existing RenderOutput coordination and destination writer. Store the invocation format selection in reporting state; do not create another reporter or delivery state. Keep existing raw writes and RenderOutput available as deliberate raw paths.

Preserve quiet-mode rendering through discard, closed-reporter handling, separate presentation evidence, and existing final outcome precedence. Do not add a context-cancellation gate to Report: handlers decide whether to submit already-acquired evidence. Do not close or flush caller writers. Avoid recursive report submission from inside a rendering callback.

Exercise rendering errors under quiet mode, a successful operation with delivery failure, a nonzero domain outcome with delivery failure, supported cause identity, and submission of acquired content after cancellation. Reuse existing reporter and outcome coverage where unchanged. Document the public handoff and raw-output boundary in GoDoc.

Stage 4: Universal format input, core version, and a core consumer

Complete. Core format selection, version reporting, and a maintained core consumer use the shared report path. Focused parser, routing, completion, and reporting tests and the root workspace suite (GOTOOLCHAIN=local go test ./... with Go 1.27.0) passed. Integration migrations remain in later stages.

Extend neutral core flag metadata and parser selection in metadata.go, parser.go, and the internal Cobra adapter. Add core-owned --format with text, yaml, and json completion. Omission means automatic; explicit empty or unknown formats are usage errors before input factories, acquisition, or handlers. Validate supplied occurrences using normal singleton conversion behavior; the last valid supplied choice selects the format. Preserve entered spellings, consumed values, --, reporting-mode ordering, and fresh invocation state. Do not treat the value-taking flag as a boolean when generating completion or reducing core flag occurrences.

Use existing core-flag placement and alias mechanisms. Reserve the long name format at installation, with no built-in short spelling. A local binding or conflicting alias source produces the existing installation collision error; a deliberate alias to core --format, such as --fmt, remains supported. Remove the version command's local format binding and switch its report to Report plus an ordinary version text template. Do not encode help, usage, completion protocol output, or diagnostic messages as reports.

Convert one maintained core consumer command to a data handoff and optional template, with no format switch. Exercise core/application reports in all three formats, unknown formats before domain work, format aliases, metadata/help without acquisition, reservation collisions, and repeated invocations. Update the core CLI and consumer reporting sections with the landed boundary; later documentation stages complete the integration inventory.

Stage 5: Public CLI JSON parsing

Complete. CLI JSON parsing and numeric conversion are implemented. Focused boundary tests and the root workspace suite (GOTOOLCHAIN=local go test ./... with Go 1.27.0) passed.

Add ParseCLIJSON(string) (any, error) in core. Decode exactly one JSON value with UseNumber, require completion of that value, and recursively convert numbers under OD-2. Integer syntax becomes int64, or uint64 for representable nonnegative overflow; decimal/exponent syntax becomes float64. Return syntax and numeric range errors; accept ordinary float approximation. Preserve nested arrays, objects, null, booleans, and strings. Keep conversion and its required policy/rationale comments in one private CLI helper. This parser is separate from report normalization.

Test nested values, signed/unsigned integer boundaries, out-of-range values, decimal and exponent syntax, floating range failures, trailing JSON, and ordinary float approximation. Do not add arbitrary-precision types or a public numeric conversion API. Each integration will enforce its flag's outer shape.

Stage 6: Ordered typed occurrences and reusable binding identity

Complete. Ordered typed occurrences and independently renamed bindings are implemented, including captured subset replay. Focused binding tests and the root workspace suite (GOTOOLCHAIN=local go test ./... with Go 1.27.0) passed.

Extend binding.go, flag_values.go, and the neutral preparation path to retain ordinal positions from existing FlagOccurrences. Add:

  • OccurrenceFlag[I,V](FlagMeta, func(string) (V,error), func(*I, Supplied[V])) Flag[I]: repeatable, converted once per supplied occurrence, no fallback occurrences; invokes its setter once per occurrence.
  • RenameFlag[I](Flag[I], name string) Flag[I]: independent binding identity, same parser/setter/default/required/completion behavior, replacement long name, and no inherited short spelling. Normal declaration validation still applies.

Apply participating occurrence bindings in actual command-line order across canonical spellings and aliases. Ordinary bindings keep their existing grouped semantics. During input construction apply ordinary flag values, then ordered occurrences, then operands, before CheckInput. The relative ordering contract is needed among participating occurrence bindings, not between arbitrary caller side effects. All conversion failures still occur before input construction.

Extend private prepared values with typed occurrence closures and ordinals. CaptureFlags retains those records against original binding identities; FlagValues.ApplyTo checks the selected subset and required presence, then replays only its participating records in order without parsing again. Repeated applications retain independent core-owned parsed collections. Preserve existing wiring-versus-usage classification; expose neither raw arguments nor backend objects. RenameFlag must preserve ordered behavior when used on such a binding.

Verify interleaved distinct flags and aliases, repeated names, explicit empty values, omitted bindings, subset selection, conversion failure, required checks, renamed handles, repeated application, and fresh invocations. Do not change the ordinary RepeatFlag replacement semantics to simulate ordering.

Stage 7: Migrate existing ckconfig reports to core

Complete. Existing ckconfig reports use shared rendering, including safe effective values and reached-scope validation aggregation. Focused integration tests and the root and ckconfig workspace suites passed with Go 1.27.0 using GOTOOLCHAIN=local go test ./... ./integrations/ckconfig/.... The ckprompt migration remains in the following stages.

Convert the existing scopes, show, sources, explain, diff, and concise validate report paths in ckconfig to the public handoff. Remove local format flags, validators, encoding switches, and encoders. Give integration-owned projections JSON tags for their selected content; thin path/location/snapshot projections remain appropriate.

For effective display, capture native WriteEffective output, call DecodeYAMLReport, and hand off that logical value without a text template. For --scope all, acquire all requested views and complete required validation before output; combine their safe values into one map keyed by scope ID, even with one registered scope. Single-scope output is unwrapped. Retire document markers and scope-comment framing; do not promise mapping order. An acquisition failure prevents the combined display. Conversion/rendering failures use the presentation path, including under quiet mode.

Keep current content where the target does not change it. Use concise text templates for scopes/source inventories and existing explanation summaries when appropriate; default diff remains a structured mapping without a template. For concise validation, collect reached-scope results before one submission; stop acquisition on failure/cancellation and preserve its outcome. Stage 20 extends that same aggregation with structured evidence rather than introducing another validation delivery path.

Verify universal formats, safe-value conversion, aggregate shape, selected single-string output, provider failure before combined display, and separate presentation failures. Replace obsolete native-byte/document-order assertions and update current display/validation contracts and the corresponding testing policy wording as behavior changes. Do not add domain comparison tests.

Stage 8: Adopt PromptKit v0.20.0 and native resource inspection

Complete. ckprompt selects released PromptKit v0.20.0 at commit 8ff9aa3efdc9f16b9d2729e0a29ea083eb3c3eaf with verified module sums and updated attribution. Native prompt, profile, and backend inspection tests, including format, callback, error, and cancellation cases, passed with Go 1.27.0. Root and ckconfig workspace suites also passed. The full ckprompt suite still encounters the remaining local format bindings scheduled for Stage 9; those bindings are not part of the completed inspection migration.

Update ckprompt's PromptKit requirement and authentic sums to v0.20.0; keep ConfigKit v1.1.0 and existing Go minima. Review the released notices and update module attribution and applicable transitive notices. Do not fabricate future CommandKit dependency sums.

Implement the resource inspection target. Remove duplicated prompt/profile report structs and per-field formatters; pass the native PromptInspection and ProfileInspection to core, without templates. Add BackendRequest{Selection ckconfig.Selection; ID string} and an independently optional Suite.InspectBackend callback returning commandkit.Acquired[*promptkit.BackendInspection]. Wire FromEngine through native InspectBackend, and install show backend BACKEND_ID when available. Stage 12 adds the common namespace field to these requests.

Use native JSON omission/presence and returned captured messages. Do not complete profile settings, infer readiness, resolve credentials, or reconstruct provenance in these commands. Preserve errors, including native backend-not-found identity, acquisition diagnostics, cancellation, and presentation failures. Adapt only fixtures and callers affected by the released API; retain legitimate collection release/version evidence.

Verify native handoff fidelity across all formats, independent callback absence, no loading for help/completion, positional IDs, omitted versus explicit resource fields, native errors, and cancellation. Assert adaptation against returned native evidence rather than rechecking upstream inheritance or rendering.

Stage 9: Consolidate remaining ckprompt reports

Move requirements show/validate, all catalogs, and smoke reports onto core rendering. Remove remaining local format bindings, allowlists, encoders, and format-specific report paths. Preserve selected report content with JSON tags and text templates where a concise text view already serves operators. Keep smoke reports as structured values without a dedicated text template.

Single smoke reports retain native returned evidence, even with an operation error. test all submits one report containing its ordered reached test results; stop under the existing operation/cancellation lifecycle and retain partial results. Core does not aggregate tests. Do not drop an acquired report merely because the context became canceled; do not fabricate a report when native preparation returned none. Preserve authentication response-limit unknown facts, preparation-error causes, and operational failures. Findings that are false, unknown, unsupported, or incomplete do not independently change command status.

Verify one JSON document for aggregation, partial report plus error, no-report preparation errors, cancellation after evidence acquisition, quiet rendering, and delivery failure without losing domain evidence. Use deterministic native fixtures/test doubles rather than network probes. Update current report guidance for the converted commands.

Stage 10: Reusable execution and resource flag collections

Implement CLI-specific collections in ckprompt using ordinary public core flags. Use typed flag-set structs exposing named original Flag[I] handles and an All() []Flag[I] convenience method; callers select subsets with ordinary slices. Constructors take a destination accessor into the application's own input type. This avoids a new core collection API, string-keyed value lookup, or enum-driven request builder.

Select these collection/value boundaries:

  • ExecutionInput holds native *ExecutionTargetOverride and *int transient retries. NewExecutionFlags supplies the eleven execution controls from OD-2 through named handles. Allocate the native override only when a relevant value is supplied; retain pointer zero/empty values and upstream scalar semantics.
  • ResourceInput holds presence-aware prompt/profile/backend/session IDs. NewResourceFlags exposes those handles independently.
  • PromptInputs holds native variables and artifact-reference maps. NewPromptInputFlags supplies variable/text/file handles; Stage 11 fills in ordered text/file construction. No application-internal execution helper is introduced.

Use canonical names from the OD-2 table. Define each name, usage, and alias relationship once in ckprompt metadata reused by Stage 13. Preserve existing scalar syntax and integer timeout units. --llm-extra-params is a singleton object parsed by ParseCLIJSON; reject a non-object through the usage path and forward an explicit empty object unchanged. Leave upstream value validation and whole-map replacement to PromptKit.

Use execution controls on validation, preview, and smoke. Profile selection is applicable to all three; prompt selection remains positional for validation and preview. Backend selection is for native smoke requests; ordinary RunRequest has no backend-selection field. Session, variables, and prompt inputs apply only to the request operations that consume them. Requirements show uses only its profile/session/variable context. Resource inspection gets no execution flags.

Retain authoritative application builders: seed the native request once, allow a complete replacement, and never reapply flags afterward. Preserve nil versus explicit retries and the different native ordinary/smoke defaults. Verify collection use with an application-owned input, selected subsets, zero/empty forwarding, JSON object parsing, and builder replacement at the boundary.

Stage 11: Ordered literal/file inputs and concrete preview

Use OccurrenceFlag for named text/file assignments. Split at the first =, preserve literal empty text, construct native Inline or File references, and assign into the same PromptInputs.Inputs map as occurrences are replayed. The last occurrence per name wins across both forms. Use canonical flags and aliases exactly as OD-2: --input now denotes literal text; file access uses --llm-input-file or its later scoped alias. Do not infer files from text. No prompt-input flags go onto smoke tests.

Add PreparationRequest carrying selection and native RunRequest, an optional Suite.PrepareRequest callback returning Acquired[*promptkit.PreparedRun], and WithRequestPreparation taking the same loader/builder pattern as WithRequestValidation. Install show prepared PROMPT_ID independently of validation/resource inspection. Forward one final built request to native Engine.Prepare exactly once; do not call ValidateRequest first or retain a prepared execution handle. Hand off native PreparedRun without a template. Stage 12 extends the common request envelope with namespace selection.

Reuse input/state preparation and diagnostics. Explain in command help that preparation does resource I/O and reports rendered application content without calling the model. No execution-success or public-disclosure guarantee.

Verify alternating text/file occurrences, duplicate names, aliases after Stage 13, empty literals, values containing =, fresh invocations, builder replacement, preview callback independence, request/context forwarding, native result/error identity, and no model invocation. Derive expected preview evidence from the native result rather than asserting PromptKit's rendering algorithm.

Stage 12: Opt-in namespace composition

Add WithNamespaces(suite, promptkit.Namespaces) Suite and store explicit application defaults in an optional suite field. Add Namespaces *promptkit.Namespaces to applicable ckprompt request envelopes, including preparation and smoke. Nil means leave the loader's view untouched. With the option enabled, start with its declared defaults and replace only supplied CLI fields, including explicit empty clearing; populate the final native value in the operation request. Native adapters apply one Engine.WithNamespaces call after loading and before the selected upstream operation.

Implement only the flags in OD-3's applicability table. Keep catalog filters and global configuration inspection separate. FromEngine callbacks and validation/preparation/smoke adapters consume request namespace selection consistently; custom callbacks receive the selection without an extra hidden loader. Builders retain authority over their native requests. Loaders using the standard option leave view-default selection to the adapter; loaders without it remain usable as before.

Explain native requirements profile identity in help, including explicit short profile selection versus the prompt's stored default reference. Do not rewrite configured references or try to make discovery profile-independent.

Verify defaults plus one override preserve unrelated defaults, explicit clearing, qualified IDs, applicable flag availability, custom loader behavior without the option, and native view/error forwarding. Test boundary equivalence, not native namespace membership or requirements-analysis correctness.

Stage 13: Generated scoped aliases and complete-family installation

Add Declarations(suite) []commandkit.Declaration, assembling the canonical family and generated exact-command FlagAliasFor rules. Retain Command(suite) for canonical-only installation. Generate aliases from the selected flags and shared metadata built in Stages 10–12, following OD-2/OD-3; do not keep a separate command-by-flag matrix. Generate only for installed commands and applicable bindings. No aliases are application-wide by default.

Use the existing routing/installation boundary, original binding identities, and conflict checks. Application-owned commands can install deliberate aliases through the public core API. Do not add subtree scopes, wrapper commands, or a new declaration-bundle type. Canonical-only help must not claim convenience aliases that were never installed.

Exercise convenient and canonical-only assembly, optional callback subsets, command aliases with scoped flag aliases, unknown/inapplicable names, native binding presence, mixed-alias occurrence order, and ordinary installation conflicts. Metadata/help/completion remain independent of engine acquisition.

Stage 14: Metadata and failed-acquisition evidence facets

Extend ckconfig contracts with Scope.Features ScopeFeatures: PathDiscovery, PathShow, and Overrides booleans. These describe optional modes within existing commands, not new subcommands. Native adapters advertise the first two; overrides remain explicit loader opt-in in Stage 16. Retain existing Operations and the six-command family. Capture features with the suite, check requested mode availability before acquisition, and include supported feature names in scope discovery/help. A declared mode missing its required acquired facet is an operational provider wiring error, not an empty successful report. Detailed validation itself remains available on validation scopes and can report unavailable native findings.

Add View.Metadata *configkit.Metadata and View.Findings *Findings, with Findings{Records []configkit.Diagnostic; Messages []commandkit.Diagnostic}. Nil findings means unavailable; a nonnil empty record set means acquired but empty. Existing View.Sources supplies optional inventory, including after an error. Keep metadata as a deliberate upstream public value dependency; no parallel metadata engine or generic diagnostic framework.

Put native-generated ordinary warning presentations in Findings.Messages, with their known association to the native record set. Keep unrelated application messages in Acquired.Diagnostics. Ordinary handlers queue both groups; detailed validation reports native records and queues only unrelated messages, so filtering does not produce duplicate ordinary warnings. Keep the existing terminal explanation, even when it describes a finding. Do not deduplicate by message text or discard caller messages with no known relationship.

Update FromConfigKit and ckprompt.ConfigScope: successful loads expose native safe writers, sources, metadata, and findings. A matched *configkit.LoadError exposes its captured Sources/Diagnostics alongside the original error. Use that error snapshot as the failure evidence rather than appending a duplicate result inventory; do not expose effective configuration or metadata from a failed load. Other failures may have no structured evidence. Keep unavailable distinct from available-empty inventory via the optional source reader. Preserve error chains and existing diagnostic severity/terminal ownership. Ordinary PromptKit loading outside ConfigScope continues its normal diagnostic delivery.

Update acquisition-report helpers to queue native presentations from their new owner without changing unaffected operations. Test both native adapters, success, matched/wrapped errors, empty versus unavailable evidence, no effective facet on failure, independently supplied diagnostics, and metadata/help without loading.

Stage 15: Independent comparison selector inputs

Replace inheritance in input.go. Add Selector.AgainstName string; an empty name declares no right-side flag. For a declared counterpart use Stage 6's RenameFlag to retain domain parsing and setter behavior with a fresh identity and no copied short alias. Capture left and right values into distinct FlagValues[I] stores. Validate name collisions through normal assembly; do not auto-generate counterpart names.

Prepare each side with a separate NewInput, applying only that side's bindings and selection. Omitted fields preserve the factory's ordinary defaults and unsupplied state. Remove inheritComparisonSelection; config and overlay counterparts also start independently. No selector value or repeatable collection is copied to the opposite side, including when that side is partly supplied. Required checks apply to the applicable declared subset on its side. Complete both input checks before one NewState and the existing pair provider call. Command-wide scope/format/detail/assertion controls stay outside side inputs. Equal selections still acquire both sides and compare.

Verify OD-9's left-only/right-only/both/neither and partial-side cases, custom repeated selectors, required inputs, supplied state, fresh invocation storage, shared state, and checks before acquisition. Keep application factory objects and caches application-owned; no arbitrary deep copying. Update selector GoDoc and replace the canonical comparison inheritance description with the selected model. Explicit-empty custom collections remain application-defined.

Stage 16: Opt-in transient override acquisition

Add Selection.Overrides []configkit.Override. Preserve ordered records; nil means no CLI records. A loader opting in via scope.Features.Overrides = true reads those records during its ordinary load and supplies them to ConfigKit. Reuse the existing loader signature instead of adding a second loader or trying to modify an already-loaded result. FromConfigKit and ConfigScope do not claim that arbitrary application loaders consume overrides automatically.

Install repeatable --set POINTER=JSON on acquisition commands (validate, show, sources, explain, and diff), and --against-set on comparisons. Scope discovery gets no acquisition flags. Parse with a shared ckconfig assignment helper: split at the first =, parse the pointer with native ConfigKit path syntax, parse one JSON value with ParseCLIJSON, and set the safe provenance label to --set or --against-set. Syntax/JSON conversion failures are usage errors. Native restrictions on admissible override paths and combinations remain load-time ConfigKit errors. Do not prevalidate root/index/schema restrictions, deduplicate, collapse records, resolve overlaps, or retry a rejected load.

Only loaders that declared support receive installed override flags for their scope; reject an unsupported selected mode before acquisition, including mixed aggregate scope coverage. Supply the same CLI records independently to each selected ordinary scope that accepts them. Copy CLI-owned record slices and parsed JSON containers when applied to independently prepared selections; do not copy arbitrary application runtime objects. For comparison, left and right lists are independent under OD-9; absence never erases application-owned overrides or inherits the other side's CLI records. No new clearing flag.

Document the unsupported = in pointer keys and preserve = in JSON values. Verify nested typed values, empty/false/zero/null, duplicate/overlapping records forwarded in order, safe labels, capability availability, comparison separation, and propagation of native load errors/provenance. Domain precedence and override algorithms remain upstream tests.

Stage 17: Explanation discovery and metadata

Extend config explain under OD-4. Track supplied --path separately from its value; root --path '' is an operation. Bare invocation shows successful command help before input/state factories or acquisition. Select --list or --path, with both a usage error. List-only flags are --historical, --under POINTER, and --explicit=true|false; reject their use in path mode or without list selection as an invalid combination rather than silently ignoring them.

For listing, require declared PathDiscovery and acquired metadata. Enumerate native HistoricalPaths, use Lookup for current presence and explicitness, and include historical-only paths only when requested. Obtain History even when Lookup is absent where detailed explanation requires it. Represent unavailable current metadata separately from false explicitness. Do not label all non-explicit values as defaults or enumerate schema fields that never existed.

Use parsed pointer token boundaries for subtree tests, including root and escaped keys. A small private pointer-token comparison can consume native paths' String representations; it must not invent another domain path parser or equate textual prefixes. Retain native paths and list indexes. Historical-only entries match neither current explicitness filter. Native path enumeration order is sufficient; do not add a new ordering guarantee.

Use a compact discovery report {scope, paths: [...]} with per-entry path, present, and optional metadata containing explicitness when current. Attach a compact text template; values/history stay out of the list. Extend path-specific explanation's existing report with native available field metadata, avoiding repeated evidence. Existing explanation remains usable when PathDiscovery is absent. Update help, GoDoc, and focused tests for mode/presence/filter behavior, capabilities, historical-only evidence, and result delivery.

Stage 18: Focused effective values and source evidence

Add config show --path POINTER for one scope with PathShow support. Parse the pointer before loading, call the acquired native Explain, and select its safe effective snapshot. An absent effective path is operational failure; explicitly present null succeeds. A historical-only explanation does not supply a current value. Convert the snapshot YAML through core and submit only the selected value, without snapshot wrappers or a text template. Whole-document aggregate show continues Stage 7's map; path plus --scope all is a usage error.

Add config sources --source-id ID to existing Sources capability. Filter the acquired inventory rather than invoking another loader. Retain the ordinary source report envelope and return its selected single entry; unknown IDs are operational failures. On acquisition error, report available captured source inventory, filtered when requested, while preserving the acquisition failure. If a filter also misses during a failed load, preserve the original cause and include the selection problem in the explanation rather than replacing the load error. If evidence is unavailable, say so; do not fabricate an empty inventory. Source IDs are local to this acquisition. Preserve native locations, version and destination evidence, and redaction in the existing thin source projection.

Verify mapping/string/false/zero/null focused display across formats, missing and historical-only paths, optional capability failure, known/unknown source selection, available-empty versus unavailable failure evidence, native cause identity, and presentation failure alongside acquisition failure. Do not read source files again to recover evidence.

Stage 19: Detailed differences and assertion outcomes

Reuse existing Scope.Compare and native Difference records. Keep concise additions/changes/deletions as default and add --details. The detailed report is {scope, differences: [...]}; entries carry native path, before, after, and hidden_changed. Each snapshot has explicit present, redacted, and a safe decoded value (null when absent, distinguished by present=false). Decode only present native snapshots; do not interpret marker-looking strings as redaction. Use one projection path and ordinary JSON tags, no mirrored upstream graph or custom omission framework. Empty differences is [], not null. Both modes have no text template, so automatic output is YAML.

Add opt-in --check. Use native record presence, including concealed changes, to return a domain outcome with status 3 for differences; equality stays status 0. Usage and operational errors retain 2 and 1 respectively. Without --check, successful differences remain success. Render the report before returning the chosen operation outcome. Preserve a nonzero domain result if presentation also fails, retaining separate presentation evidence under core outcome rules.

Verify the same provider calls/loads serve concise and detailed views, native additions/deletions, null versus absence, hidden changes with equal safe values, empty results, sequence snapshots remaining atomic, all formats, and assertion outcomes with writer/render failure. Do not compute equality from displayed YAML, add a comparison callback, reload data, or implement list matching.

Stage 20: Detailed validation and reached-scope aggregation

Complete Stage 7's validation aggregation using Stage 14's evidence. Add --details, repeatable --severity, and repeatable --code on validation; filters require detailed mode. Parse severity using native known severities; codes remain exact native code strings, including future/unmatched strings. Within one filter match any selected value; across filters match both. Filter only presentation, never operation outcome.

Acquire scopes in existing order, stopping at first acquisition failure or cancellation. Retain completed-scope results and available evidence from the failing/reached scope. Do not create records claiming unvisited scopes passed. Submit once after acquisition stops, even if cancellation caused the stop. This handler must not use an ordinary inspection helper's pre-submission cancellation guard. Keep native-generated messages in their existing diagnostic lifecycle; aggregate report timing does not buffer the whole invocation.

Use one report {scopes: [...]} in concise and detailed modes. Each entry names the scope and its outcome (valid, failed, or canceled); detailed entries add findings adapted from native records with safe source references, and distinguish unavailable, empty, filtered, and present evidence states. Use existing thin path/location/source projections, converting native Paths to operator pointer strings instead of serializing their private storage. Keep required sources for selected findings, including related locations. Apply the known-group warning coordination from Stage 14, preserving unrelated messages and the terminal failure explanation. Concise mode retains ordinary warnings and a compact text template; detailed mode has the selected readable text template with scope/outcome followed by findings and locations. Explicit YAML/JSON renders that same selected report value.

A failed load establishes no effective configuration. Successfully rendering its evidence never changes failure to success. Preserve cancellation/load cause and separate presentation failure. Output errors occur after acquisition has stopped and cannot undo loads or stop loads already completed. Update the CLI and tests that formerly stopped on per-scope output failures.

Verify success, warnings, matched load failure, unavailable/empty evidence, filters with no matches, source references, known duplicate suppression, unrelated warnings, aggregate failure/cancellation, one JSON document, quiet mode, and combined operation/presentation failures. Avoid exact cosmetic snapshots and upstream validation-rule tests.

Stage 21: Simple consumer and core/configuration API exercise

Update the maintained simple ckconfig consumer to install an explicitly configured FromConfigKit scope with Overrides enabled, replacing AppCommand convenience wiring there. Append the selected native CLI records to its ordinary ConfigKit Options.Overrides during loading, leaving native conflict handling intact. Declare explicit right-side names for any selected application selectors. Keep ordinary configuration discovery/default behavior on omitted sides. Demonstrate metadata listing, focused values, detailed validation, source filtering, detailed diff, and assertions through the standard family, not custom duplicate handlers.

Use the existing before/after fixtures and add fixtures/invalid.yml with a valid schema header plus greeting: [invalid], which cannot decode into the example string field. Use it for acquired-source and diagnostic delivery, not to independently test upstream type validation. Extend existing consumer tests for a representative normal task, a failed-load evidence task, and an independent comparison/override task. Reuse lower-layer parsing and rendering coverage; do not duplicate the full mode matrix here. Show a structured application report and text template in the core consumer without optional integration imports. Ensure metadata-only operations do not initialize application runtime state.

Stage 22: Composed consumer and application-owned flag reuse

Update the maintained composed consumer to install ckprompt.Declarations, explicit empty native namespace defaults (enabling root defaults plus opt-in selectors), request preparation, extended ConfigScope facets, and explicit against-campaign/against-limit comparison bindings for their existing applicable scopes. Opt the application scope into overrides and append its CLI records to ordinary ConfigKit overrides; native duplicate/overlap errors remain native errors. Reuse the public CLI flag collections on an application-owned command with its own input type, showing canonical-only behavior there unless it deliberately installs aliases. Do not introduce application-internal upstream convenience wrappers.

Keep the PromptKit configuration scope's Overrides feature false in this consumer. Released PromptKit Config/ConfigurationSources accept sources but do not expose a ConfigKit Options.Overrides handoff. OD-11 is explicitly a loader opt-in; it does not require simulating missing native engine support through source rewriting. All native inspection/evidence features remain enabled. Application-owned loaders can declare override support when their own acquisition boundary actually accepts those records. Aggregate --set preflight must account for this scope difference rather than dropping an unsupported scope silently.

Keep successful-load caching application-owned and based on each side's complete selection, overrides, and supplied domain inputs. A source-selection-only cache must not incorrectly reuse a result for different overrides or comparison sides. Use a small invocation-local cache-entry list and reflect.DeepEqual on owned selections and relevant supplied domain fields, retaining those inputs with each entry. Do not invent a universal hash scheme or cache across invocations. Retain invocation state lifetime and do not cache failed loads as successes.

Update request fixtures to use released resource/source contracts and explicit file-input names. Include short inline input, preview, namespaces, and effective provider parameters. Keep the native default bundle and existing domain commands unless the selected target changes their usage; do not freeze catalog counts. Retain the local fake LLM/probe setup and native finding-versus-operation outcome semantics. No external credentials or model services in default examples/tests.

Exercise representative config and prompt workflows, aliases and presence, builder replacement, rendered preview, failure evidence, independent campaign selections with overrides, ordinary domain dispatch, and help/version without loading. Expected native evidence should derive from the selected engine/result; do not reimplement native resolution tests.

Stage 23: Canonical contracts and obsolete infrastructure audit

Review every path in the feature roadmap's output inventory. Remove remaining handler-local format inputs, validators, encoders, legacy prompt/profile mirrors, inherited comparison helpers, and old document framing. Do not route raw help, diagnostics, shell protocols, or intentional caller raw writes through report serialization. Remove direct integration YAML dependencies only if no legitimate domain/fixture usage remains after go mod tidy.

Complete GoDoc and CLI reference updates: universal formats, representation and text-template behavior, native resources versus prepared content, flags and scoped aliases, mode/capability availability, metadata and failure evidence, independent selections/overrides, outcomes, cancellation, and changed aggregate show/validation delivery. Remove obsolete migration sections and legacy variants from current guidance as required by the clean-adoption scope. Historical released notes and tags stay immutable.

Update the consumer guide, current internal inventory, applicable README/development examples, dependency guidance, and testing policy's obsolete native-YAML/order requirements. Refer to upstream for domain semantics rather than copying a parallel specification. Align architecture-policy wording that describes the former shared comparison selectors with the deliberate new model; do not add unrelated policy changes or successor ADRs for these presentation/selector choices. Use maintained examples as complete artifacts.

Check scope against all roadmap completion criteria and deferred exclusions. Perform focused documentation/link/fragment, whitespace, notices, and API-boundary review. No new generic report framework, runtime wrappers, output-contract or appended-message flags, persistence, live probes, discovery tracing, or secret bootstrap work enters this sprint.

Stage 24: Core release candidate and publication handoff

Inspect authoritative release state under the release procedure before selecting versions. Use the next unused core minor release (expected v0.4.0 if still unused), a later ckconfig minor release (expected v0.4.0), and update ckprompt v0.3.0 only if it remains unpublished. If that candidate has been published, preserve it and select the next unused minor instead. These are mechanical applications of the existing release policy, not new product decisions. Record actual versions and source commits here as they become available.

Prepare the core note, notices, and canonical contracts for the full shared reporting/input API, with immutable footer links. Explain changed core contracts concisely; no compatibility adapter or separate migration guide. Use the selected release toolchain for root standalone tests and the normal candidate preparation. Commit the reviewed candidate before any publication.

Core publication is a maintainer handoff requiring separate explicit authorization. This plan does not authorize push, tags, publication, or hosted delivery. Without that authorization, finish all available workspace development and candidate work, report the release dependency pending, and do not claim final independent integration validation. Do not add polling, CI gates, or an alternative fake module release to bypass this handoff. After authorized source publication, proceed to Stage 25. Hosted delivery remains a separate operation.

Stage 25: Released core alignment and ckconfig candidate

Pin the actual released core version supplying Stages 1–6 in both integrations. Download ckconfig dependencies with GOWORK off and collect authentic sums; tidy that module with the selected toolchain. Defer ckprompt standalone preparation until Stage 26 supplies its released ckconfig requirement. Keep ConfigKit v1.1.0 and PromptKit v0.20.0. Verify core's module graph still has no optional integration dependency.

Run ckconfig's standalone suite with released core and its maintained simple consumer. Prepare and commit the ckconfig minor note, attribution, dependency metadata, and applicable guidance. The note covers shared reporting, new CLI modes/override opt-in, independent selections, and assertions directly, with the module-specific immutable footer. Do not edit older released notes.

Publication of this candidate is the second separately authorized maintainer handoff. Until it occurs, ckprompt workspace results remain useful but do not prove its independent dependency graph. Preserve that distinction in status. After authorized ckconfig source publication, continue with its real released version; hosted delivery remains separately tracked under the release procedure.

Stage 26: Final ckprompt alignment and end-to-end verification

Pin released core and ckconfig versions providing the new APIs in ckprompt. Download and tidy with GOWORK off; retain real sums. Update the unpublished ckprompt candidate note (or fresh minor selected in Stage 24) with the final capabilities and pinned dependencies, correct product/version title, and module-specific immutable licensing footer. Record final module identities here. No code may depend on the temporary workspace to hide old requirements.

With Go 1.27.0 selected, run the independent suites from the repository root:

GOWORK=off GOTOOLCHAIN=local go test ./...
(cd integrations/ckconfig && GOWORK=off GOTOOLCHAIN=local go test ./...)
(cd integrations/ckprompt && GOWORK=off GOTOOLCHAIN=local go test ./...)

Then validate the aligned workspace:

GOTOOLCHAIN=local go test ./...
GOTOOLCHAIN=local go test ./integrations/ckconfig/...
GOTOOLCHAIN=local go test ./integrations/ckprompt/...

Confirm tidy produces no remaining module changes after preparation. Format changed Go files and check public facade/backend import direction, documentation links/fragments, attribution pins, intended files, and staged/unstaged whitespace. Use graph tools first for code discovery and ordinary searches for literals, configuration, and docs. Reuse successful checks for unchanged content; root ./... alone is not integration coverage.

Run maintained consumers outside the workspace for these representative tasks, using their final installed features and fixtures:

  • Automatic and explicit text/YAML/JSON application/version reports.
  • Whole/aggregate/focused config display; metadata listing and root explanation.
  • Independent campaign/config comparisons, --details, --check, and both override sides, including zero/null/list values through standard syntax.
  • Invalid-load sources and detailed validation retaining a nonzero operation outcome, and all-scope validation producing one reached-scope report.
  • Native prompt/profile/backend inspection; prepared preview with inline and file inputs, aliases, namespaces, and provider parameters; requirements validation.
  • A deterministic single smoke and test all with the configured local client, retaining native findings and separate operation/presentation semantics.

From integrations/ckconfig/examples/simple, representative final invocations are:

GOWORK=off GOTOOLCHAIN=local go run . config explain --list
GOWORK=off GOTOOLCHAIN=local go run . config show --path /greeting --format json
GOWORK=off GOTOOLCHAIN=local go run . config diff --config fixtures/before.yml --against-config fixtures/after.yml --details
GOWORK=off GOTOOLCHAIN=local go run . config validate --config fixtures/invalid.yml --details --format json
GOWORK=off GOTOOLCHAIN=local go run . config sources --config fixtures/invalid.yml

The invalid-load invocations intentionally fail while reporting available evidence. From integrations/ckprompt/examples/composed, run:

GOWORK=off GOTOOLCHAIN=local go run . config show --scope all --format json
GOWORK=off GOTOOLCHAIN=local go run . config validate --scope all --campaign spring --limit=0 --details
GOWORK=off GOTOOLCHAIN=local go run . config diff --scope app --campaign spring --limit=0 --against-campaign autumn --against-limit=0 --details
GOWORK=off GOTOOLCHAIN=local go run . config diff --scope app --set '/campaigns/spring/model="left"' --against-set '/campaigns/spring/model="right"' --details
GOWORK=off GOTOOLCHAIN=local go run . promptkit show prompt briefing --campaign spring --prompt-namespace field-notes
GOWORK=off GOTOOLCHAIN=local go run . promptkit show profile spring --campaign spring
GOWORK=off GOTOOLCHAIN=local go run . promptkit show backend local --campaign spring
GOWORK=off GOTOOLCHAIN=local go run . promptkit show prepared briefing --campaign spring --input topic=sprint --profile spring --extra-params '{"campaign":"preview"}'
GOWORK=off GOTOOLCHAIN=local go run . promptkit requirements validate briefing --campaign spring --input-file topic=fixtures/topic.txt
GOWORK=off GOTOOLCHAIN=local go run . promptkit test all --campaign spring --prompt briefing --profile spring

Record actual outcomes and final fixture identities. Use existing consumer tests to assert native application statuses (including --check status 3); the go run wrapper itself does not preserve a child program's nonzero status code. Existing focused unit/integration tests own injected cancellation and writer failures; do not build another exhaustive consumer harness. Default verification stays offline after dependencies are prepared.

Audit each completed stage against its behavior and the feature roadmap, remove leftover migration scaffolding, review the complete diff, and commit the final candidate. Keep feature/implementation status accurate and preserve deferred items in future.md when retiring completed records under repository policy. ckprompt publication and hosted delivery remain separate authorized operations; preparing this candidate does not perform them. Do not mark the full dependency alignment complete until both preceding release handoffs and independent suites have actually succeeded.

Open Questions

None requiring a product or scope decision. API and transition choices are selected above. Core and ckconfig publication authorization is an explicit external dependency in Stages 24–25, already required by OD-7 and release policy; it is not implicit authority granted by an implementation prompt. Exact unused versions and release commits are established from authoritative state at those handoffs, without weakening independent-module completion criteria.