173 lines
10 KiB
Markdown
173 lines
10 KiB
Markdown
# Configuration Input Destinations Roadmap
|
|
|
|
Status: implemented. This roadmap records the approved behavior and rationale
|
|
for the [PromptKit feature request](promptkit-feature-request.md). The
|
|
completed implementation plan is preserved in Git history at
|
|
`315f464:docs/roadmap/implementation.md`, including its audit and remediation
|
|
evidence; the [configuration contract](../config.md#input-destinations)
|
|
owns current behavior.
|
|
|
|
## Targeted end state
|
|
|
|
A consumer can assign a mapping destination to a configuration input and perform
|
|
one ordinary `LoadLayered` call. The input's application content contributes
|
|
beneath that destination while retaining normal composition, precedence,
|
|
inheritance, typed loading, diagnostics, and inspection. PromptKit can assemble
|
|
collections without parsing and rewriting sources, merging values, or rebuilding
|
|
provenance itself.
|
|
|
|
For example, a fragment defining `summarize.alerts` can contribute beneath
|
|
`collections`, `weatherreporter`, `prompts`. An independent source with the same
|
|
local key can contribute beneath another collection without conflict. Collection
|
|
and prompt names remain ordinary application keys, not ConfigKit namespaces.
|
|
|
|
The public surface adds an optional `Destination Path` field on `Input`, not a
|
|
new loading entry point or an operation on completed results. Content-bearing
|
|
main inputs and underlay inputs support
|
|
the same destination model; root placement remains the default.
|
|
|
|
The following behavior defines the target:
|
|
|
|
- Omitted and empty destinations retain root placement. Destinations consist of
|
|
literal mapping keys, including dots, slashes, and numeric-looking text.
|
|
Explicit sequence-index destinations are outside the requested capability.
|
|
- A valid destination on `NoSource` contributes nothing. An actual empty
|
|
application mapping materializes its destination mappings as explicit input,
|
|
matching authored wrappers, without clearing lower-tier children.
|
|
- Existing structural reservations apply to introduced mappings. Destinations
|
|
that materialize `configkit` or a mapping-valued `extends` contrary to existing
|
|
contracts fail through the structured loading-error boundary. Keys merely
|
|
containing those words remain ordinary keys.
|
|
- Host files, native filesystem files, bytes, readers, and mapping sources all
|
|
support placement under their existing acquisition and ownership contracts.
|
|
Filesystem context, import opt-in, and precedence remain independent choices.
|
|
- Mounted contributions have the same application values and conflict behavior
|
|
as explicitly wrapped contributions, with accurate original source locations.
|
|
Disjoint mappings combine; overlapping non-mapping values within a group
|
|
conflict even when equal. A later tier cannot repair a strict-group conflict.
|
|
- Different destinations can coexist in one group, and the same destination can
|
|
occur in different tiers. Ancestor/descendant destinations follow ordinary
|
|
composition and overlay rules without namespace uniqueness restrictions.
|
|
Later tiers recursively overlay mappings and replace other values. Empty
|
|
mappings do not clear lower values; sequences remain atomic.
|
|
- A prompt's ordinary `version` override changes that field and retains omitted
|
|
lower fields. It neither identifies a merge record nor replaces a whole prompt.
|
|
- Source-root `configkit.imports` remains structural. Imported application data
|
|
inherits the input destination transitively. Import paths still resolve from
|
|
their declaring source; containment, optionality, cycles, and repeated-source
|
|
rules remain applicable. Placement does not change physical source identity.
|
|
- Sibling inheritance runs after assembly in the effective destination scope.
|
|
Peer fragments can supply a child and its sibling parent. Qualified PromptKit
|
|
references do not acquire cross-collection inheritance meaning.
|
|
- Version ownership is enforced at effective application paths. A collection's
|
|
mounted `version` is ordinary data, while underlay/import contributions to the
|
|
actual protected path, or replacements of its ancestors, remain invalid.
|
|
There is one main-owned version check and no blanket nested numeric conversion.
|
|
- Defaults, decoding, resolution, secret lookup, and validation run once on the
|
|
assembled application, not independently on fragments. Callbacks and value
|
|
diagnostics use effective paths. Failures use structured load errors and yield
|
|
no usable partial result.
|
|
- Presence, provenance, history, explanations, effective rendering, and diffs
|
|
agree with the final values. Sensitivity is evaluated at effective application
|
|
paths under the existing historical and dependency rules.
|
|
- Existing source records expose placement, including inherited import
|
|
placement. Introduced ancestor mappings retain the contributing source's
|
|
identity; any root-location fallback identifies that document, not an authored
|
|
wrapper. Actual content retains its real source coordinates.
|
|
- Original source locations and passive resource contexts survive placement,
|
|
overrides, and inheritance. `Result.SourceContext` and
|
|
`Resolution.SourceContext` still identify the declaring filesystem and base
|
|
directory for a field such as `content_file: ./summary.md`.
|
|
- Destinations and the structure they introduce participate in existing load
|
|
limits; placement cannot bypass depth or node accounting. Source ownership,
|
|
complete-on-return loading, and detached result behavior remain intact.
|
|
|
|
Import-destination syntax, independent collection specification headers, and
|
|
cross-collection inheritance are separate possible follow-ups. This work does
|
|
not add directory discovery, collection installation, remote acquisition,
|
|
namespace ownership enforcement, dependency solving, live reload, filename-based
|
|
identity, arbitrary transformations, or new merge strategies. PromptKit owns its
|
|
collection inventory, qualified IDs, and execution semantics.
|
|
|
|
## Implementation baseline (v0.7.1)
|
|
|
|
The request reviewed v0.7.1. At that baseline, the relevant boundaries were:
|
|
|
|
- [Input](../../layered.go) holds a source, import opt-in, and filesystem context,
|
|
but no destination. Root types delegate to the engine through the existing
|
|
[facade boundary](../internal/overview.md).
|
|
- [Layered loading](../config.md#layered-loading) already provides strict groups,
|
|
ordered precedence, shared acquisition budgets, and one final lifecycle.
|
|
[Underlay acquisition](../../internal/engine/load_request.go) gathers source
|
|
applications and recomposes them into their strict group.
|
|
- [Input acquisition](../../internal/engine/load_input.go) and
|
|
[import traversal](../../internal/engine/imports.go) process source-root
|
|
directives and source identity before final assembly. Imported version claims
|
|
are checked during traversal; underlay claims are checked before group
|
|
composition. These currently operate without a destination.
|
|
- [Version claim checks](../../internal/engine/directives.go) inspect a document
|
|
using the configured application path. Wrapping only an already acquired
|
|
result would leave early fragment checks and diagnostic paths incorrect.
|
|
- [Sibling inheritance](../adr/0009-sibling-inheritance.md) already runs after
|
|
source precedence and preserves source-to-destination derivation. Placement
|
|
must feed that existing mechanism rather than resolve fragments independently.
|
|
- Existing source records identify acquisition and precedence but do not expose
|
|
input placement. Existing history retains source applications, so moving only
|
|
the final tree would be insufficient for coherent inspection.
|
|
|
|
The architectural fit is an extension of input assembly, not a parser extension
|
|
or a second configuration model. The
|
|
[architecture policy](../policy/architecture.md) supplies the ownership and
|
|
consistency constraints; [deferred scope](deferred.md) continues to govern the
|
|
unrequested features above.
|
|
|
|
## Selected Design Decisions
|
|
|
|
### Main-input destinations and absent inputs
|
|
|
|
Allow the same destination model for content-bearing main inputs and underlays,
|
|
with `VersionRule.Path` remaining an effective application path and any
|
|
specification declaration still owned by main. The checker retains its existing
|
|
handling of an absent declaration and its existing lifecycle phase. `NoSource`
|
|
contributes nothing even with a valid destination. This keeps `Input` coherent
|
|
across its roles and preserves absence without per-fragment version checks.
|
|
|
|
### Public placement inspection and synthetic ancestors
|
|
|
|
Expose effective placement as `SourceInfo.Destination Path` on existing source
|
|
records, including inherited import placement.
|
|
Use original source identity for introduced ancestor mappings, documenting that
|
|
any root-location fallback identifies the contributing document rather than a
|
|
physically authored wrapper. Actual content keeps its real coordinates. This
|
|
allows consumers to connect placement to sources without a new query system.
|
|
|
|
Preserve that relationship through inherited fields, composite origins, and the
|
|
same source selected in separate tiers. Placement is per source application;
|
|
consumers can inspect it without inferring it from final paths.
|
|
|
|
### Reserved structural keys in destinations
|
|
|
|
Use existing `Path` conventions for literal keys and parsed
|
|
numeric tokens, reject explicit index segments, and preserve current structural
|
|
reservations in the effective tree. Reject destination segments that would
|
|
materialize `configkit` or a mapping-valued `extends` contrary to those contracts,
|
|
with a clear structured destination error. Ordinary keys containing those words,
|
|
dots, or slashes remain ordinary keys. Source-root directives are processed before
|
|
placement and are not rejected simply because their application body is mounted.
|
|
|
|
Mounted and authored wrappers therefore retain the same structural meaning.
|
|
Destination diagnostics identify placement as the cause of invalid introduced
|
|
structure, using existing error categories where suitable.
|
|
|
|
### Empty mappings and presence of introduced containers
|
|
|
|
Mounting an actual empty application mapping materializes its
|
|
destination mappings as explicit contributions, matching authored wrappers.
|
|
This preserves the request's equivalence principle and lets consumers inspect
|
|
an intentionally empty collection. Such mappings still do not clear lower-tier
|
|
children. An absent source contributes nothing.
|
|
|
|
This applies equally to empty imported application bodies and inputs containing
|
|
only import directives. Presence follows the contribution's meaning rather than
|
|
whether an implementation happened to allocate wrapper nodes.
|