Files
ConfigKit/docs/roadmap/relative-import-destinations.md

132 lines
7.3 KiB
Markdown

# Relative Import Destinations Roadmap
Status: planned; syntax selected and implementation has not started. The
[implementation plan](implementation.md) owns sequencing and completion evidence.
This roadmap addresses only the relative-import-destination addition in
the [PromptKit request](promptkit-feature-request.md#requested-addition-relative-import-destinations).
Independent source specification headers are deferred for reconsideration after
this work is implemented; they are not a prerequisite or part of this feature.
## Targeted end state
Authors can assign a relative mapping destination to a `path` or `glob` import.
ConfigKit appends its literal key segments to the immediate importing document's
effective destination, then processes the imported application content through
the existing placement and loading lifecycle. Applications continue to select
entry sources, input destinations, filesystem contexts, and precedence tiers.
Selected YAML syntax:
```yaml
configkit:
imports:
- path: metadata.yml
- glob: prompts/*.yml
destination: [prompts]
- glob: profiles/*.yml
destination: [profiles]
```
If the application places this entry at `[collections, weather]`, its metadata
import contributes at that same path, and each prompt file contributes at
`[collections, weather, prompts]`. An import declared inside a prompt file with
`destination: [extras]` contributes at
`[collections, weather, prompts, extras]`. A subsequent sibling import from the
entry is still relative to `[collections, weather]`.
This example does not declare or consume a source specification header. A
source-local `version` remains ordinary payload unless governed by the existing
main-owned version contract. The combined header example in the broader request
is not an acceptance requirement for this roadmap.
The feature must preserve these requested and existing behaviors:
- Omission and an empty destination list retain the importing document's
destination. Each glob match receives the same relative placement. Transitive
imports accumulate destinations from their immediate parents.
- An explicit `destination` is a sequence of strings. Null, scalar values, and
non-string members are invalid directive shapes; values are not coerced.
For a numeric-looking key, use a string such as `destination: ["0"]`.
- Segments are mapping keys under the existing `Input.Destination` rules. Dots,
slashes, and numeric-looking text within a key are literal. There is no
filesystem-style normalization, parent traversal, or application-root reset.
Do not add a collection-name grammar or reject otherwise supported literal
keys merely because their spelling resembles a filesystem path.
- Imports retain their strict-composition tier. Placement and traversal order
do not confer precedence. Later tiers retain existing recursive overlay
behavior; sequences remain atomic and overlapping destinations use existing
composition rules.
- Filesystem paths resolve from their declaring source independently of logical
placement. Import opt-in, optionality, glob behavior, containment, cycle and
repeated-source rules, source kinds, and ownership remain unchanged. A new
destination does not allow a physical source to repeat within a strict group.
- Source-root directives are interpreted before application placement. Existing
reserved-key rules continue to apply to destinations. Invalid new directive
shapes produce normal structured failures rather than being ignored.
- `SourceInfo.Destination` reports each acquired source's resulting effective
destination, including nested imports and sources recorded on failed loads
to the extent supported by existing error reporting.
- Composition and value diagnostics use effective application paths and real
source locations. Directive errors identify their source-local declaration.
Placement does not manufacture authored coordinates or alter resource bases.
- Main-owned version protection applies at the resulting effective paths.
Ordinary nested version fields stay ordinary payload. Inheritance resolves
in the assembled sibling scope, then defaults, decoding, resolution, secret
lookup, and validation follow the existing single-load lifecycle.
- Presence, provenance, history, explanations, rendering, diffs, and sensitivity
agree with the placed contributions. Source-relative resource contexts survive
inheritance and precedence under their existing contracts.
- Accumulated placement and introduced wrappers participate in existing depth
and node accounting. This work does not select new limit values or promise
new performance bounds. An actually imported empty mapping retains existing
placement behavior; an optional import that finds no source creates no payload.
The syntax is available wherever existing explicit imports are supported,
including ordinary root loading and layered main/underlay inputs. It does not
require a new Go loading entry point, mount registry, or consumer-side rewriting.
Source header policies and consumption, cross-collection inheritance, sequence
merging, root-reset syntax, automatic discovery, recursive glob syntax, and
collection management are outside this delivery. This scope statement does not
establish new permanent exclusions beyond [existing deferred scope](deferred.md).
## Current baseline
Reviewed baseline: `315f464`, with input destinations implemented. The
[configuration contract](../config.md#input-destinations) and
[ADR 0011](../adr/0011-input-destinations.md) describe that feature.
- [Directive parsing](../../internal/engine/directives.go) accepts `path` or
`glob` plus `optional`; it rejects unrecognized fields. Import declarations
currently carry no relative destination.
- [Import traversal](../../internal/engine/imports.go) holds one destination for
an input's entire import tree. Both document placement and imported source
records use it. Per-document effective placement is therefore required.
- [Input acquisition](../../internal/engine/load_input.go) currently assigns
the input destination to all returned imported source records. That uniform
assignment must no longer overwrite distinct import destinations.
- [Destination helpers](../../internal/engine/destination.go) already validate
literal mapping paths, place document bodies, and check introduced depth and
node costs. Composition, version protection, and retained source applications
already operate on placed content.
- The root facade already exposes `SourceInfo.Destination`; the new syntax can
use that inspection surface without a separate placement API.
The change extends traversal and directive parsing. It should reuse existing
placement and assembly rather than introduce a second merge or validation model.
## Selected Design Decision
### YAML destination representation
Use `destination` as a sequence of strings, for example
`destination: [prompts, "0"]`. Omission and `[]` inherit placement. Null, scalar
destinations, and non-string members are invalid shapes rather than values to
coerce. Every string key allowed by existing destination rules remains valid,
including the empty string.
This representation directly expresses literal segments and keeps numeric key
text distinct from YAML numbers. It provides one explicit notation consistent
with the existing mapping-destination model. These shape rules define the new
directive syntax; other configuration values retain their existing semantics.