Plan relative import destinations
This commit is contained in:
231
docs/roadmap/relative-import-destinations.md
Normal file
231
docs/roadmap/relative-import-destinations.md
Normal file
@@ -0,0 +1,231 @@
|
|||||||
|
# Relative Import Destinations Roadmap
|
||||||
|
|
||||||
|
Status: planned; implementation has not started. Execute the stages below in
|
||||||
|
order. 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 these stages.
|
||||||
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
Proposed syntax, pending the syntax decision below:
|
||||||
|
|
||||||
|
```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.
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
## Ordered implementation plan
|
||||||
|
|
||||||
|
### 1. Select syntax and document the semantic extension
|
||||||
|
|
||||||
|
Resolve the Open Decision below and specify valid shapes, literal key handling,
|
||||||
|
and structured failures. Preserve existing `path`/`glob` and `optional` behavior.
|
||||||
|
Validate declared destination syntax even when an optional import has no match;
|
||||||
|
optionality suppresses missing input, not malformed directives.
|
||||||
|
|
||||||
|
Record the extension to ADR 0011's inherited-destination model in a new ADR
|
||||||
|
without rewriting the accepted decision. Distinguish the new declarative syntax
|
||||||
|
from unchanged input placement and version ownership. Review compatibility
|
||||||
|
under the release policy without choosing or publishing a release in this work.
|
||||||
|
|
||||||
|
Completion: the syntax and parent-relative semantics are explicit, with source
|
||||||
|
specification headers still deferred and no additional merge or namespace rules.
|
||||||
|
|
||||||
|
### 2. Parse destinations and carry effective placement through traversal
|
||||||
|
|
||||||
|
Extend private import declarations and parser validation with the selected
|
||||||
|
relative destination representation and useful declaration locations. Reuse
|
||||||
|
existing key validation rather than maintaining a competing path convention.
|
||||||
|
|
||||||
|
Compute each child's effective destination from the immediate parent's placement.
|
||||||
|
Pass that context through path imports, glob expansion, and recursive traversal.
|
||||||
|
Explicit per-call state is a straightforward implementation option; the public
|
||||||
|
contract need not prescribe a parameter, stack, or allocation layout. Ensure
|
||||||
|
nested placement cannot leak into siblings, subsequent glob matches, or inputs.
|
||||||
|
|
||||||
|
Use the resulting destination when placing the body, checking effective version
|
||||||
|
claims, accounting for limits, and creating source records. Remove or narrow
|
||||||
|
uniform post-traversal source-destination assignment. Retain original physical
|
||||||
|
identity and resource contexts; do not include destination in repetition keys.
|
||||||
|
|
||||||
|
Completion: nested and sibling imports, glob matches, and source records all use
|
||||||
|
the right effective destination, with structured errors and existing bounds.
|
||||||
|
|
||||||
|
### 3. Verify integration with assembly and inspection
|
||||||
|
|
||||||
|
Check that placed source applications feed existing strict composition, tier
|
||||||
|
precedence, inheritance, and final typed loading. Confirm conflicts report the
|
||||||
|
effective path and contributing physical locations, including imports that
|
||||||
|
collide with explicitly wrapped input or a destination ancestor.
|
||||||
|
|
||||||
|
Verify protected version claims after destination accumulation, and ordinary
|
||||||
|
version payload away from the protected path. Confirm history, sensitivity,
|
||||||
|
rendering, and diffs use placed data without reconstructing placement in callers.
|
||||||
|
Exercise inherited and surviving lower-tier resource references through existing
|
||||||
|
source-context APIs. Preserve detached source records and existing failure
|
||||||
|
behavior; do not add promises about collecting every error or exact failure
|
||||||
|
ordering merely to simplify tests.
|
||||||
|
|
||||||
|
Completion: imports with explicit destinations agree with equivalent existing
|
||||||
|
placement for application behavior, while actual source attribution stays intact.
|
||||||
|
|
||||||
|
### 4. Add acceptance coverage and consumer guidance
|
||||||
|
|
||||||
|
Use parser tests for declaration shape, engine tests for traversal and placement,
|
||||||
|
and public tests/examples for complete consumer workflows. Reuse existing tests
|
||||||
|
where they already protect unchanged behavior. Cover the following distinct risks:
|
||||||
|
|
||||||
|
| Scenario | Evidence required |
|
||||||
|
| --- | --- |
|
||||||
|
| Omitted destination and `[]` | Existing inherited placement, including root imports |
|
||||||
|
| Entry, child, and grandchild destinations | Placement accumulates from the immediate importer |
|
||||||
|
| Nested import followed by a sibling; multiple glob matches | Child state does not leak to peers |
|
||||||
|
| Literal slash, dot, numeric-looking, and empty keys | Existing mapping-key meaning is preserved |
|
||||||
|
| Invalid shapes and reserved keys, including optional unmatched imports | Structured directive failure with a real declaration location |
|
||||||
|
| Disjoint, overlapping, and ancestor-related destinations | Existing composition conflicts and tier precedence |
|
||||||
|
| Same physical source selected at different destinations in a group | Existing repetition/cycle policy is retained |
|
||||||
|
| Mounted import targeting a protected version path | Existing ownership checks use the accumulated path |
|
||||||
|
| Ordinary version payload elsewhere | No new checking, coercion, or consumption |
|
||||||
|
| Inheritance, overrides, and resource-relative fields | Effective paths and original resource bases agree |
|
||||||
|
| History, classified values, and diffs | Existing provenance and disclosure rules remain effective |
|
||||||
|
| Accumulated depth, wrapper nodes, empty bodies, and absent optional sources | Existing accounting and contribution behavior |
|
||||||
|
| Host/native filesystem imports and supported entry source forms | Placement is independent of acquisition kind |
|
||||||
|
| Public source inspection and load failures | Accurate effective destinations and detached records |
|
||||||
|
|
||||||
|
Add an executable collection-entry example that imports metadata and mounts
|
||||||
|
prompt/profile fragments. It must use no source header checker or consumer-side
|
||||||
|
parsing, merging, or provenance reconstruction. Demonstrate ordinary root loading
|
||||||
|
as well as a representative layered mounted entry without duplicating all cases.
|
||||||
|
|
||||||
|
Update the owning configuration contract and consumer guide as behavior lands;
|
||||||
|
update source-record declaration documentation and internal overview only where
|
||||||
|
their descriptions change. Keep the header proposal deferred for later review.
|
||||||
|
|
||||||
|
Run focused tests, then the everyday check and appropriate ownership race checks
|
||||||
|
from the [development guide](../development.md), following the
|
||||||
|
[testing policy](../policy/testing.md). Validate documentation links. No independent
|
||||||
|
performance benchmarks are part of this roadmap.
|
||||||
|
|
||||||
|
Completion: the relative-import acceptance scenarios in the PromptKit request
|
||||||
|
are covered, the combined workflow works without source headers, validation
|
||||||
|
passes, and implemented documentation matches the behavior. Source specification
|
||||||
|
headers can then be reconsidered as a separate feature; their implementation is
|
||||||
|
not required to complete this roadmap.
|
||||||
|
|
||||||
|
## Open Decisions
|
||||||
|
|
||||||
|
### YAML destination representation
|
||||||
|
|
||||||
|
Recommendation: adopt `destination` as a sequence of strings, for example
|
||||||
|
`destination: [prompts, "0"]`. Omission and `[]` inherit placement. Treat null,
|
||||||
|
scalar destinations, and non-string members as invalid shapes rather than
|
||||||
|
coercing them. Permit every string key allowed by existing destination rules,
|
||||||
|
including the empty string. This directly expresses literal segments, matches
|
||||||
|
the request's example, and keeps numeric key text distinct from YAML numbers.
|
||||||
|
These shape choices are proposed syntax, not pre-existing restrictions.
|
||||||
|
|
||||||
|
Alternative: also accept a scalar JSON-pointer representation using existing
|
||||||
|
`ParsePath` conventions, while retaining the sequence form. This is viable and
|
||||||
|
may be convenient for users already familiar with public paths, but introduces
|
||||||
|
two spellings and escaping rules for one operation. A leading slash would still
|
||||||
|
describe relative segments, not reset to the application root, which could be
|
||||||
|
surprising. Prefer the sequence-only form unless consumer evidence justifies
|
||||||
|
the additional notation. A null-as-inherit shorthand is also viable but adds a
|
||||||
|
third spelling for behavior already covered by omission and an empty list.
|
||||||
Reference in New Issue
Block a user