Settle input destination roadmap decisions

This commit is contained in:
2026-10-14 12:40:06 +00:00
parent 3c2d7facb3
commit 6353598bd6

View File

@@ -1,10 +1,10 @@
# Configuration Input Destinations Roadmap
Status: proposed; implementation has not started. Execute the stages below in
order. This roadmap responds to the
Status: design decisions approved; implementation has not started. Execute the
stages below in order. This roadmap responds to the
[PromptKit feature request](promptkit-feature-request.md) and owns the target
state, delivery sequence, and unresolved design choices. Public spelling and
recommendations below are proposals until selected explicitly.
state, delivery sequence, and selected design decisions. Public API spelling and
diagnostic details remain to be finalized during implementation planning.
## Targeted end state
@@ -22,14 +22,21 @@ and prompt names remain ordinary application keys, not ConfigKit namespaces.
The intended public surface is per-input placement, illustratively an optional
`Destination Path` field on `Input`, not a new loading entry point or an operation
on completed results. The minimum supported workflow has a root main input and
mounted underlay inputs; broader main placement is an open decision below.
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.
@@ -62,6 +69,10 @@ The following behavior defines the target:
- 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
@@ -113,9 +124,9 @@ unrequested features above.
### 1. Settle placement semantics and the public contract
Resolve the Open Decisions before their dependent implementation. Select the
public API spelling, main/NoSource behavior, placement inspection, reserved-key
handling, and empty-contribution semantics. Define destination validation and
Finalize public API spelling using the Selected Design Decisions below for
main/NoSource behavior, placement inspection, reserved-key handling, and
empty-contribution semantics. Define destination validation and
structured errors, including when validation occurs relative to source access.
Use existing error categories where suitable rather than inventing a parallel
error system.
@@ -192,7 +203,7 @@ or executable example, reusing existing coverage where it proves the same
behavior. Include focused cases for:
- omitted/empty destinations, literal escaped and numeric keys, invalid index
destinations, and the selected reserved-key and main-input rules;
destinations, and the approved reserved-key and main-input rules;
- different destinations, shared destinations, ancestor overlaps, equal and
unequal conflicts, explicit null, omitted fields, and empty contributions;
- recursive precedence, atomic sequences, and domain-version-only overrides;
@@ -222,45 +233,33 @@ Completion: all requested public scenarios pass, owning documentation describes
implemented behavior, and consumers can perform one complete layered load with
no compensating source-rewriting or post-load structural pass.
## Open Decisions
## Selected Design Decisions
### Main-input destinations and absent inputs
Recommendation: allow the same destination model for content-bearing main inputs
as for 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. Treat `NoSource` as no contribution,
even with a valid destination. This keeps `Input` coherent and avoids a role-only
restriction. PromptKit can continue using root main; broader main placement must
not add per-fragment checks or move the existing version-check phase.
Alternative: initially support non-root destinations only for underlay inputs
and reject non-root main placement explicitly. This meets PromptKit's minimum
need and reduces the first implementation's version-check interactions, but adds
a role-dependent rule to a shared public type. Adopt that restriction only as an
explicit scope choice, not because threading main placement is inconvenient.
For `NoSource`, rejecting a nonempty destination could catch mistaken assembly
declarations, but makes an otherwise absent contribution less composable.
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
Recommendation: expose effective placement on existing source records,
Expose effective placement on existing source records,
illustratively `SourceInfo.Destination`, 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.
Alternative: add placement to origin records or a dedicated lookup, and represent
synthetic ancestors without a physical location. This can distinguish authored
and synthetic structure more precisely, but expands per-value metadata or adds
an API when placement is fundamentally per source application. Evaluate the
choice against inherited fields, composite origins, and the same source selected
in separate tiers; do not infer placement from a final path by guesswork.
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
Recommendation: use existing `Path` conventions for literal keys and parsed
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,
@@ -268,25 +267,18 @@ 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.
Alternative: permit structural spellings as literal synthetic wrapper keys by
distinguishing them from authored directives. This enables additional application
paths but introduces an exception where mounted and explicitly wrapped inputs
can have different meanings. It would require an explicit change to reserved-key
semantics and is not needed for the requested collection paths. Running existing
directive validation on the placed tree is another viable error mechanism, but
must still identify that the invalid structure came from destination selection.
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
Recommendation: mounting an actual empty application mapping materializes its
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.
Alternative: treat an empty mounted body as no contribution. This avoids empty
containers for fragments containing only imports or no application fields, but
loses equivalence with explicitly wrapped empty mappings and erases an observable
presence distinction. If selected, document that exception and its effect on
history and empty imported bodies rather than deriving it accidentally from
whether the implementation allocated wrapper nodes.
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.