Plan configuration input destination implementation
This commit is contained in:
432
docs/roadmap/implementation.md
Normal file
432
docs/roadmap/implementation.md
Normal file
@@ -0,0 +1,432 @@
|
|||||||
|
# Implement configuration input destinations
|
||||||
|
|
||||||
|
Status: planned. Execute Stage 1 through Stage 12 in order, one focused stage
|
||||||
|
per Luna implementation prompt. The [feature roadmap](input-destinations.md)
|
||||||
|
owns the approved behavior and rationale; the
|
||||||
|
[consumer request](promptkit-feature-request.md#public-acceptance-scenarios)
|
||||||
|
supplies the public acceptance scenarios. This document owns execution and
|
||||||
|
completion evidence. Planning baseline: `6353598`.
|
||||||
|
|
||||||
|
## Working instructions
|
||||||
|
|
||||||
|
- Start each stage with `AGENTS.md`, [development.md](../development.md), the
|
||||||
|
applicable policies, and working-tree inspection. Use graph-first code
|
||||||
|
discovery. Preserve unrelated changes and previously completed stages.
|
||||||
|
- Implement only that stage and its supporting tests/documentation. Mark it
|
||||||
|
complete here with actual commands and evidence, then commit the nonempty
|
||||||
|
validated unit with a short plain-English message. Subsequent stages remain
|
||||||
|
planned. A stage is not complete solely because its narrow tests pass.
|
||||||
|
- Keep early mechanics private until the complete engine behavior is ready.
|
||||||
|
Root destination fields land in Stage 10. Ordinary root loading must remain
|
||||||
|
working throughout. Do not publish a partially supported public placement API.
|
||||||
|
- Follow the existing engine/document/YAML boundaries. Reuse strict composition,
|
||||||
|
recursive overlay, sibling inheritance, paths, history, and sensitivity.
|
||||||
|
No dependencies, toolchain changes, alternate mergers, mount registry,
|
||||||
|
per-fragment lifecycle, import-destination syntax, resource discovery, or new
|
||||||
|
release gates are needed. These are scope boundaries, not new prohibitions
|
||||||
|
on separately approved future work.
|
||||||
|
- Update current-behavior documentation when public behavior lands; keep future
|
||||||
|
claims here or in the roadmap until then. Add the ADR in Stage 1 under the
|
||||||
|
documentation policy's accepted-decision exception.
|
||||||
|
- Use focused offline tests while iterating; run `./scripts/check.sh` before
|
||||||
|
committing production changes. Documentation-only stages need whitespace and
|
||||||
|
local-link checks. Stage 12 adds full ownership/race validation. Tests protect
|
||||||
|
observable behavior, not wrapper allocation or helper-call counts. Reuse
|
||||||
|
coverage rather than repeat an entire loading matrix at every layer.
|
||||||
|
- No benchmark campaign or public complexity guarantee is required. Prefer
|
||||||
|
straightforward bounded walks and wrapping each acquired contribution once;
|
||||||
|
avoid rescanning all preceding contributions for every new input.
|
||||||
|
- Do not push, tag, publish, update downstream dependencies, or retire unfinished
|
||||||
|
records. Release compatibility review is separate from publication.
|
||||||
|
|
||||||
|
## Resolved implementation decisions
|
||||||
|
|
||||||
|
1. Add root-owned `Input.Destination Path` and `SourceInfo.Destination Path`,
|
||||||
|
mirrored privately in engine input/source records. Extend `loadInput` and
|
||||||
|
explicit root/engine conversion and cloning. No new loading entry point,
|
||||||
|
public wrapper type, option, or origin field is needed. Ordinary `Load`
|
||||||
|
continues to supply root placement.
|
||||||
|
2. The zero path means root. Validate `Path.valid()` and reject every explicit
|
||||||
|
index segment, including a negative index. Normalize parsed tokens to literal
|
||||||
|
mapping-key segments: `/0` means the key `0`, not sequence element zero.
|
||||||
|
Empty, dot, dot-dot, slash-containing, tilde-containing, and numeric keys keep
|
||||||
|
existing semantic-path meaning. Do not split dots, interpret filesystem
|
||||||
|
traversal, enforce identifier grammar, or add namespace uniqueness.
|
||||||
|
3. Reject destination segments equal to `configkit` or `extends`: placement
|
||||||
|
would introduce a reserved mapping key with a mapping value. Substrings such
|
||||||
|
as `myextends` are ordinary keys. This preserves the approved structural
|
||||||
|
rules rather than adding an application naming policy. Source-root import
|
||||||
|
directives are still processed before placement.
|
||||||
|
4. Validate destination shape/reservations for all declared inputs during
|
||||||
|
grouped option preflight, before reading any source. Reuse
|
||||||
|
`CodeOptionsInvalid` for invalid destination declarations; include the
|
||||||
|
offending semantic path when representable, with no fabricated physical
|
||||||
|
location. An invalid source still follows existing source-option validation.
|
||||||
|
A valid destination on `NoSource` contributes no nodes, source record, or
|
||||||
|
budget charges. No extra error type or exact message contract is introduced.
|
||||||
|
5. Separate acquired source syntax from application placement. Retain original
|
||||||
|
parsed source metadata for filesystem/directive handling. Strip source-root
|
||||||
|
directives, then wrap each application body at the normalized destination
|
||||||
|
before fragment version checks and strict composition. Imports inherit the
|
||||||
|
same destination transitively. Do not wrap both a source application and its
|
||||||
|
recomposed result; every retained application must already use effective
|
||||||
|
coordinates. Content roots remain mappings under existing source contracts.
|
||||||
|
6. Wrapping a body at `Keys("a", "b")` creates `{a: {b: body}}` as private
|
||||||
|
document mappings. Actual body nodes and entries keep their physical source
|
||||||
|
coordinates. Introduced mappings/entries use the contributing document's root
|
||||||
|
location as a documented source fallback, not purported authored coordinates.
|
||||||
|
They have the same contributing source ID and create no synthetic source.
|
||||||
|
Retained history trees remain immutable and separate from assembly mutation.
|
||||||
|
7. A present empty body creates explicit destination mappings, including an
|
||||||
|
import-only source whose application body is empty. It still cannot clear
|
||||||
|
lower mappings. A missing optional import and `NoSource` remain absent. Empty
|
||||||
|
source text remains the existing invalid document, not an empty mapping.
|
||||||
|
8. `VersionRule.Path` stays an effective application path. Check main once after
|
||||||
|
its own imports compose and before underlays/overlay/CLI, at the existing
|
||||||
|
phase. Imported and underlay claims are checked against placed application
|
||||||
|
content, including scalar/null/sequence ancestors replacing a protected path.
|
||||||
|
A mapping ancestor with no protected descendant is not a version claim.
|
||||||
|
Mounted domain `version` fields are ordinary data. Existing inheritance,
|
||||||
|
selected-overlay, CLI protection and exact-path numeric conversion remain;
|
||||||
|
no nested blanket conversion or additional fragment checker is introduced.
|
||||||
|
9. Placement does not alter physical source identity, filesystem namespace,
|
||||||
|
source IDs, acquisition order, imported-from locations, or resource contexts.
|
||||||
|
Repeated physical sources in one strict group still fail even at different
|
||||||
|
destinations. The same physical source in separate tiers retains the existing
|
||||||
|
independent source applications/records and each record's own destination.
|
||||||
|
Overlay and CLI source records have root `Destination`; they are not mounted
|
||||||
|
merely because main is mounted. Active layered overlays retain their explicit
|
||||||
|
independent filesystem selection and application-root meaning.
|
||||||
|
10. Value-level paths use effective coordinates. Keep genuine source-local
|
||||||
|
import-directive diagnostics and parse/read failures at their original
|
||||||
|
locations; do not invent a logical child path when parsing cannot identify
|
||||||
|
one. Prefix existing application-relative diagnostic paths exactly once
|
||||||
|
where available. Preserve structured codes, related physical locations,
|
||||||
|
deterministic ordering, and value-free messages.
|
||||||
|
11. Use current depth/node limits, not a new destination cap. With root depth
|
||||||
|
zero, each destination segment adds one level and, under `countInputNodes`,
|
||||||
|
one mapping node plus one key. Retain current raw input accounting (including
|
||||||
|
directives); charge only the additional `2 * segmentCount` synthetic nodes
|
||||||
|
per acquired body, once, to the shared input budget. Placement adds no bytes,
|
||||||
|
acquired sources, import nesting, or glob visits. Validate placed application
|
||||||
|
depth and per-document node bounds before composition; share accounting
|
||||||
|
across inputs and imports. Precheck wrapper depth/count before allocating
|
||||||
|
wrappers. Use existing source/import limit diagnostics in their acquisition
|
||||||
|
contexts; retain projection, expansion, and history bounds independently.
|
||||||
|
Root placement adds no charge or new rejection. NoSource adds none either.
|
||||||
|
12. Cloned source records include independently owned destination paths at every
|
||||||
|
existing publication boundary: results, load errors, metadata/inspection,
|
||||||
|
callback input information, and root conversion. Passive resource contexts
|
||||||
|
remain keyed by the real source identity; inspection must work without an
|
||||||
|
open configuration handle after load. This does not extend caller-owned
|
||||||
|
filesystem or callback resource lifetimes.
|
||||||
|
|
||||||
|
## Stage 1 — Record the decision and capture the baseline
|
||||||
|
|
||||||
|
Status: planned. Scope: decision record and evidence, no feature code.
|
||||||
|
|
||||||
|
1. Read the roadmap, request, relevant policies, and ADRs 0001, 0003, 0006,
|
||||||
|
0008, and 0009. Inspect the owners identified in the roadmap and the function
|
||||||
|
map below. Confirm the baseline and worktree before starting.
|
||||||
|
2. Run `./scripts/check.sh`; record the commit, Go version, and results here.
|
||||||
|
Locate existing coverage for root loading, strict underlays, version ownership,
|
||||||
|
repeated sources, history, resource contexts, and detached records.
|
||||||
|
3. Write `docs/adr/0011-input-destinations.md` after confirming the number is
|
||||||
|
unused. Record the approved input-placement decision as Accepted, with the
|
||||||
|
roadmap owning implementation status. Follow the repository ADR format.
|
||||||
|
Focus on ConfigKit, put rejected options only in Alternatives Considered,
|
||||||
|
and avoid negative parallelism elsewhere. No PromptKit-specific semantics.
|
||||||
|
4. Record the compatibility assessment under the release policy: adding fields
|
||||||
|
preserves zero-value/keyed-literal use, but callers using unkeyed literals
|
||||||
|
for `Input` or `SourceInfo` must migrate to keyed literals. Treat the feature
|
||||||
|
as minor-release work; select a version and write its note only during
|
||||||
|
separately authorized release preparation.
|
||||||
|
|
||||||
|
Validate: local-link test and whitespace checks. Done: baseline evidence and
|
||||||
|
the decision are recorded; implemented contracts remain unchanged.
|
||||||
|
|
||||||
|
## Stage 2 — Add private destination normalization and wrapping
|
||||||
|
|
||||||
|
Status: planned. Scope: pure private mechanics with bounded unit tests.
|
||||||
|
|
||||||
|
1. Add a small engine helper file for normalized mapping-only destinations and
|
||||||
|
constructing placed document bodies. Follow decisions 2–7; keep helpers
|
||||||
|
private and avoid introducing a second path abstraction.
|
||||||
|
2. Validate invalid paths, explicit indices, and exact reserved tokens. Normalize
|
||||||
|
parsed numeric tokens into keys, preserving literal text and pointer escaping.
|
||||||
|
3. Build wrappers without mutating the supplied tree. Preserve body locations;
|
||||||
|
give introduced entries/mappings the source-root fallback. Implement depth and
|
||||||
|
node measurement/prechecks usable with existing limits, including the extra
|
||||||
|
synthetic-node count; aggregate charging is wired in Stage 7.
|
||||||
|
4. Cover root identity/equivalence, nested empty mapping, literal/escaped/numeric
|
||||||
|
keys, invalid index/path, exact versus substring reserved keys, owned paths,
|
||||||
|
unchanged body coordinates, and bounded wrapper checks. Do not count helper
|
||||||
|
invocations or fix an allocation strategy in tests.
|
||||||
|
|
||||||
|
Validate: focused destination/path tests and the everyday check. Done: the
|
||||||
|
mechanism is usable privately; no loader accepts a new public field yet.
|
||||||
|
|
||||||
|
## Stage 3 — Integrate private non-import input placement
|
||||||
|
|
||||||
|
Status: planned. Scope: engine request plumbing and ordinary acquired bodies.
|
||||||
|
|
||||||
|
1. Add destination fields to engine `Input`, `loadInput`, and `SourceInfo`.
|
||||||
|
Preserve ownership through engine `LoadLayered` request construction,
|
||||||
|
`cloneSourceInfo`, and source-record copies. Keep the root facade unchanged.
|
||||||
|
2. Extend grouped preflight to validate/normalize destinations before source
|
||||||
|
reads. Use the existing diagnostic accumulator and options-invalid category.
|
||||||
|
Ordinary `Load` supplies root placement through its existing request adapter.
|
||||||
|
3. Thread placement into `assembleBaseInputTracked` without confusing raw
|
||||||
|
`parsedSource` with effective `assembledInput.document`. Preserve the root
|
||||||
|
path through existing wrappers/callers. For imports-disabled acquisition,
|
||||||
|
validate disabled directives on raw content, place the body, and retain the
|
||||||
|
destination on the acquired source record. NoSource still short-circuits.
|
||||||
|
4. Use engine loads to cover mounted main and underlay bodies, omitted versus
|
||||||
|
explicit root destinations, empty mapping versus NoSource, and preflight
|
||||||
|
rejection without consuming a test-owned reader. Reuse current source-kind
|
||||||
|
acquisition tests; full source equivalence is verified publicly in Stage 10.
|
||||||
|
|
||||||
|
Validate: destination, grouped-load, source, and existing ordinary-load tests;
|
||||||
|
the everyday check. Done: private non-import placement reaches assembly, with
|
||||||
|
root behavior unchanged. Imports are the next private integration step.
|
||||||
|
|
||||||
|
## Stage 4 — Carry placement through import acquisition
|
||||||
|
|
||||||
|
Status: planned. Scope: source-local directives and placed imported applications.
|
||||||
|
|
||||||
|
1. Thread a normalized destination through `loadImportedDocumentsTracked`,
|
||||||
|
`loadImportedWithAccessTracked`, and `importTraversal`, retaining root defaults
|
||||||
|
for current private callers. Place the selected body's application content
|
||||||
|
after `splitImportDirectives`; do the same for every imported body.
|
||||||
|
2. Set placement on selected/imported source records, including error records
|
||||||
|
once a source has been acquired. Keep `ImportedFrom` at the physical directive.
|
||||||
|
Run imported `fragmentVersionClaim` against placed bodies and retain placed
|
||||||
|
bodies in `state.documents` before `composeDocuments` builds applications.
|
||||||
|
3. Leave filesystem joins, containment, glob traversal, optional missing inputs,
|
||||||
|
active cycles, visited identities, and acquisition IDs/order unchanged.
|
||||||
|
Destination must not become part of the repeated-source identity key.
|
||||||
|
4. Test native and host transitive imports, nested source-root directives,
|
||||||
|
import-only bodies, and mounted imported protected versus ordinary version
|
||||||
|
paths. Verify a repeated file at two destinations in one group still fails,
|
||||||
|
including an import/direct-input alias. Reuse cycle/containment regressions.
|
||||||
|
|
||||||
|
Validate: focused destination/import/glob/grouped tests and everyday check.
|
||||||
|
Done: every retained imported contribution has effective placement and physical
|
||||||
|
source identity, with no double wrapping or application-level directive leakage.
|
||||||
|
|
||||||
|
## Stage 5 — Complete strict tiers and main version ownership
|
||||||
|
|
||||||
|
Status: planned. Scope: assembly and version interactions, not a new merger.
|
||||||
|
|
||||||
|
1. Review `acquireUnderlayGroup`: version checks must use placed content, and
|
||||||
|
documents taken from `acquired.composition.applications` must already be
|
||||||
|
placed. Recompose strict peers with ordinary `composeDocuments`; preserve
|
||||||
|
per-source applications, origins, UnderlayIndex, and input accounting.
|
||||||
|
2. In `executeLoadRequest`, main's version check uses its placed main/import
|
||||||
|
composition at the existing point. `assembleLayeredInput` recursively overlays
|
||||||
|
completed underlay groups beneath main, selected overlay, and CLI as before.
|
||||||
|
Do not mount the final assembly or prepend main's destination to upper tiers.
|
||||||
|
3. Test disjoint same-destination peers, different destinations, equal and unequal
|
||||||
|
conflicts, ancestor/descendant destinations, and a strict conflict despite an
|
||||||
|
upper override. Verify recursive mapping overlays, atomic sequences, null,
|
||||||
|
explicit false/zero, and version-only domain overrides retaining lower fields.
|
||||||
|
4. Exercise mounted main with a nested VersionRule, absent root declarations,
|
||||||
|
imported/underlay direct and ancestor claims, and nonclaiming mapping ancestors.
|
||||||
|
Check the hook runs once and does not inspect each fragment independently.
|
||||||
|
Preserve exact configured-path integer conversion and ordinary nested typing.
|
||||||
|
|
||||||
|
Validate: destination/composition/overlay/version/grouped tests and everyday
|
||||||
|
check. Done: placed and authored equivalents agree on values and conflicts;
|
||||||
|
main ownership and lifecycle timing are preserved.
|
||||||
|
|
||||||
|
## Stage 6 — Reconcile diagnostic coordinate systems
|
||||||
|
|
||||||
|
Status: planned. Scope: useful paths without fictional source locations.
|
||||||
|
|
||||||
|
1. Audit early acquisition, import, fragment-version, and composition failures.
|
||||||
|
Use one narrow path-prefix translation where diagnostics genuinely identify
|
||||||
|
application content; do not blanket-prefix every diagnostic or double-prefix
|
||||||
|
diagnostics already produced by placed trees.
|
||||||
|
2. Preserve syntax/read/directive locations and related import sites. Value
|
||||||
|
conflicts and later typed/resolver/validation failures use effective paths
|
||||||
|
but original content coordinates. Invalid introduced structure identifies
|
||||||
|
the destination declaration rather than a nonexistent source wrapper line.
|
||||||
|
3. Add focused assertions for a mounted conflict with two real sources, a mounted
|
||||||
|
decode or validation error, an imported version error, invalid destination,
|
||||||
|
and malformed source-local directives. Test stable codes/paths/locations and
|
||||||
|
nil results, not whole messages or callback choreography.
|
||||||
|
|
||||||
|
Validate: destination/diagnostic/import/version/decode tests and everyday check.
|
||||||
|
Done: diagnostics consistently distinguish application paths from source syntax.
|
||||||
|
|
||||||
|
## Stage 7 — Complete shared placement accounting
|
||||||
|
|
||||||
|
Status: planned. Scope: resource bounds with no new public limit system.
|
||||||
|
|
||||||
|
1. Wire Stage 2's prechecks and synthetic-node charges into both tracked ordinary
|
||||||
|
acquisition and import traversal, using `importAccounting` and current limit
|
||||||
|
structures. Charge each source body once, including empty import bodies.
|
||||||
|
2. Preserve existing raw byte/source/node accounting and imported directive
|
||||||
|
inspection. Additional wrappers count in per-body depth/node checks and
|
||||||
|
shared aggregate nodes; recomposition must not charge them again. Ensure
|
||||||
|
selected overlays and CLI start from totals including placement charges.
|
||||||
|
3. Test below/at/above relevant bounds using small private limit fixtures where
|
||||||
|
existing seams permit; add a narrow private seam if necessary. Cover deep
|
||||||
|
body plus destination, many shallow mounted inputs, imported wrappers, and
|
||||||
|
empty mappings. Verify root placement and NoSource do not add charges.
|
||||||
|
Preserve history/expansion limits; do not turn fixture values into defaults.
|
||||||
|
|
||||||
|
Validate: destination/limit/import/override tests and everyday check. Done:
|
||||||
|
placement cannot bypass current budgets and introduces no unrelated caps.
|
||||||
|
|
||||||
|
## Stage 8 — Preserve provenance, history, and source resource contexts
|
||||||
|
|
||||||
|
Status: planned. Scope: engine inspection and retained evidence.
|
||||||
|
|
||||||
|
1. Audit `compositionOrigins`, `completeCompositionOrigins`, application replay,
|
||||||
|
metadata construction/finalization, and source-record cloning against placed
|
||||||
|
applications. Prefer feeding placed trees into existing processing rather
|
||||||
|
than adding another path-offset index or rewriting final metadata afterward.
|
||||||
|
2. Verify explicit destination containers, actual leaves, composite origins,
|
||||||
|
superseded/removed descendants, and root/source fallbacks. Historical and
|
||||||
|
effective indexes keep independently owned paths and existing shape semantics.
|
||||||
|
3. Preserve source-ID resource contexts through imports, surviving lower-tier
|
||||||
|
values, and inheritance. Test completed-result and resolution-time context
|
||||||
|
queries against real relative files, without making ConfigKit open the
|
||||||
|
referenced application resource or retain loading handles.
|
||||||
|
4. Exercise the same physical source in separate tiers with different placement,
|
||||||
|
inspect each source record, and verify independent destination paths. Repeat
|
||||||
|
inspection after comparison and independent loads to detect retained mutation.
|
||||||
|
|
||||||
|
Validate: destination/metadata/provenance/history/resource tests,
|
||||||
|
`go test -race ./internal/engine`, and everyday check. Done: inspection explains
|
||||||
|
effective placement and physical origin without consumer reconstruction.
|
||||||
|
|
||||||
|
## Stage 9 — Verify final inheritance, sensitivity, and lifecycle integration
|
||||||
|
|
||||||
|
Status: planned. Scope: complete private engine behavior before facade exposure.
|
||||||
|
|
||||||
|
1. Resolve sibling inheritance only after full source precedence using the
|
||||||
|
existing expansion path. Cover a child and parent supplied by separate peers,
|
||||||
|
nested destination-local siblings, cancellation, and an inherited relative
|
||||||
|
resource retaining its declaring context. Cross-collection search is unchanged.
|
||||||
|
2. Reuse existing inheritance-version, overlay, and CLI guards; add targeted
|
||||||
|
mounted cases for actual protected paths and their ancestors. Do not reject
|
||||||
|
unrelated inheritance merely because it shares a mapping ancestor.
|
||||||
|
3. Test effective-path secret predicates, field tags and recorded dependencies,
|
||||||
|
superseded classified values, safe effective output/history/explanation, and
|
||||||
|
bilateral diff redaction using disposable canaries. Compare mounted versus
|
||||||
|
explicitly wrapped loads for equal effective values and no differences.
|
||||||
|
4. Verify defaults, decoding, resolution, secret lookup, and validation execute
|
||||||
|
once on the final shape; failures return no usable result. Reuse existing
|
||||||
|
ordinary-load lifetime/ownership coverage and add mounted protection where
|
||||||
|
placement creates a distinct risk.
|
||||||
|
|
||||||
|
Validate: destination/inheritance/secret/sensitivity/explain/diff/lifecycle tests
|
||||||
|
and everyday check. Done: all approved engine semantics work together without
|
||||||
|
per-fragment loading or a post-return processing pass.
|
||||||
|
|
||||||
|
## Stage 10 — Expose the root-owned facade and public acceptance tests
|
||||||
|
|
||||||
|
Status: planned. Scope: the two public fields and complete consumer behavior.
|
||||||
|
|
||||||
|
1. Add `Input.Destination Path` and `SourceInfo.Destination Path` to root types.
|
||||||
|
Extend `toEngineInput`, `fromEngineSourceInfo`, `toEngineSourceInfo`, and all
|
||||||
|
source publication paths with owned conversion. Run existing public/import
|
||||||
|
boundary tests; expose no engine nodes, aliases, or bridge methods.
|
||||||
|
2. Document zero/root behavior, mapping-only paths, main/underlay parity,
|
||||||
|
inherited import placement, source-coordinate fallback, and source ownership
|
||||||
|
beside declarations. Update the configuration contract for implemented input
|
||||||
|
destinations, preserving canonical ownership of shared semantics.
|
||||||
|
3. Add external-package public-load coverage for equivalent host file, native
|
||||||
|
fs.FS file, byte, reader, and Mapping sources. Cover default/root destinations,
|
||||||
|
literal escaped/numeric keys, empty mapping, NoSource, and invalid declarations.
|
||||||
|
Include one public mounted main case, not just underlays.
|
||||||
|
4. Add representative public tests tying final configuration to metadata,
|
||||||
|
source placement, history, resources, callbacks, and safe diffs. Mutate returned
|
||||||
|
record copies and repeat queries/loads to confirm detachment. Reuse engine
|
||||||
|
matrices; public tests demonstrate supported integration rather than every
|
||||||
|
private branch. Confirm failed loads expose detached source destinations.
|
||||||
|
|
||||||
|
Validate: `go test . -run 'Destination|Facade|PublicFacadeBoundary|DependencyImportBoundary'`,
|
||||||
|
`go test -race ./...`, and everyday check. Done: the requested workflow is usable
|
||||||
|
entirely through ConfigKit's supported import path and documented surface.
|
||||||
|
|
||||||
|
## Stage 11 — Add maintained simple and collection-style consumer examples
|
||||||
|
|
||||||
|
Status: planned. Scope: executable adoption examples with consumer-owned types.
|
||||||
|
|
||||||
|
1. Add a minimal mounted-fragment example using `Input.Destination` in an
|
||||||
|
ordinary layered load. Show literal keys and root-default compatibility
|
||||||
|
without introducing consumer parsing or generic merge helpers.
|
||||||
|
2. Add one representative collection assembly under `examples/consumers`: peer
|
||||||
|
prompt/profile fragments, collection metadata with ordinary `version`, a
|
||||||
|
source-root import, local sibling inheritance, and an intentional higher-tier
|
||||||
|
version-only override retaining the body. Keep the application VersionRule
|
||||||
|
main-owned. Use a controlled native filesystem or temporary files.
|
||||||
|
3. Demonstrate effective-path inspection plus source-relative resource lookup
|
||||||
|
during resolution and from the result, including an inherited/surviving field.
|
||||||
|
Application code owns opening/interpreting the resource and any qualified IDs.
|
||||||
|
4. Add tests for final values, presence, actual source placement/coordinates,
|
||||||
|
resource context, and expected conflict behavior. Link maintained examples
|
||||||
|
from the consumer guide; add a small executable root example if useful for
|
||||||
|
discovery without duplicating the complete scenario.
|
||||||
|
|
||||||
|
Validate: `go test ./examples/consumers`, applicable `Example` tests, local links,
|
||||||
|
and everyday check. Done: simple and representative consumers substantiate the
|
||||||
|
same configuration model and need no compensating structural pass.
|
||||||
|
|
||||||
|
## Stage 12 — Reconcile documentation and audit the complete implementation
|
||||||
|
|
||||||
|
Status: planned. Scope: final integration audit and evidence, not release work.
|
||||||
|
|
||||||
|
1. Update README navigation, consumer guidance, the component overview, and
|
||||||
|
development reading/test maps. Add ADR 0011 to navigation. Update architecture
|
||||||
|
policy only as needed to recognize placement within existing assembly and
|
||||||
|
source ownership, linking precise behavior to the configuration contract.
|
||||||
|
Do not change unrelated policies, deferred boundaries, or published notes.
|
||||||
|
2. Audit every resolved decision, roadmap behavior, and request acceptance row
|
||||||
|
against implementation and tests. Record the corresponding test names here;
|
||||||
|
for reused coverage explain the behavior it proves. Do not mark complete
|
||||||
|
based on green tests that do not exercise mounting.
|
||||||
|
3. Review the complete baseline-to-candidate diff for accidental strengthening:
|
||||||
|
extra naming rules, namespace uniqueness, main-only restrictions, changed
|
||||||
|
merge/version semantics, invented source-read ordering guarantees, new limits,
|
||||||
|
or expanded secret policies. Remove temporary helpers/unsupported branches
|
||||||
|
left by staged integration. Confirm original source coordinates remain real.
|
||||||
|
4. Run `./scripts/check.sh` and
|
||||||
|
`GOTOOLCHAIN=local GOPROXY=off go test -race ./...`. Review source-kind and
|
||||||
|
placement ownership coverage, error disclosure, complete-on-return handling,
|
||||||
|
and root/private boundaries. Record commit, Go version, results, and any
|
||||||
|
limitations. No release command, CI waiting, benchmark, or downstream upgrade.
|
||||||
|
5. Mark this plan and the roadmap implemented only when code, public examples,
|
||||||
|
and owning contracts agree. Retain completed planning evidence until separately
|
||||||
|
authorized release preparation.
|
||||||
|
|
||||||
|
Done: one complete layered load supports input destinations with coherent values,
|
||||||
|
diagnostics, inspection, limits, and source ownership across the approved surface.
|
||||||
|
|
||||||
|
## Implementation owner map
|
||||||
|
|
||||||
|
Use graph tools to locate these symbols rather than assume line numbers:
|
||||||
|
|
||||||
|
- Public input forwarding: `layered.go`, `records.go`, `conversion.go`
|
||||||
|
(source conversions), and existing facade tests.
|
||||||
|
- Private request and lifecycle: `internal/engine/layered.go`, `load_request.go`
|
||||||
|
(`loadInput`, `acquireUnderlayGroup`, `assembleLayeredInput`), `load.go`
|
||||||
|
(`executeLoadRequest`), and `load_input.go` (`assembleBaseInputTracked`).
|
||||||
|
- Directives and imports: `directives.go` (`splitImportDirectives`,
|
||||||
|
`fragmentVersionClaim`), and `imports.go` (`visitPath`).
|
||||||
|
- Shared document semantics: `compose.go`, `document_walk.go`
|
||||||
|
(`countInputNodes`), `path.go`, `parse.go`, and `value_operation.go` limits.
|
||||||
|
- Inspection: `metadata.go`, `history.go`, `explain.go`, `resource_context.go`,
|
||||||
|
`inheritance_origin.go`, `render.go`, and `diff.go`; source copies live in
|
||||||
|
engine `records.go`. Confirm current filenames through the component overview.
|
||||||
|
|
||||||
|
## Open Questions
|
||||||
|
|
||||||
|
None required for implementation. The four policy choices are approved; this
|
||||||
|
plan selects API spelling, validation timing/error category, coordinate handling,
|
||||||
|
and accounting within them. Surface a newly discovered incompatibility or scope
|
||||||
|
change with evidence rather than resolving it by silently narrowing the feature
|
||||||
|
or strengthening an unrelated contract.
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
# Configuration Input Destinations Roadmap
|
# Configuration Input Destinations Roadmap
|
||||||
|
|
||||||
Status: design decisions approved; implementation has not started. Execute the
|
Status: design decisions approved; implementation has not started. This roadmap
|
||||||
stages below in order. This roadmap responds to the
|
responds to the [PromptKit feature request](promptkit-feature-request.md) and owns
|
||||||
[PromptKit feature request](promptkit-feature-request.md) and owns the target
|
the target state and selected design decisions. The
|
||||||
state, delivery sequence, and selected design decisions. Public API spelling and
|
[implementation plan](implementation.md) owns sequencing, implementation details,
|
||||||
diagnostic details remain to be finalized during implementation planning.
|
and completion evidence.
|
||||||
|
|
||||||
## Targeted end state
|
## Targeted end state
|
||||||
|
|
||||||
@@ -20,9 +20,9 @@ For example, a fragment defining `summarize.alerts` can contribute beneath
|
|||||||
local key can contribute beneath another collection without conflict. Collection
|
local key can contribute beneath another collection without conflict. Collection
|
||||||
and prompt names remain ordinary application keys, not ConfigKit namespaces.
|
and prompt names remain ordinary application keys, not ConfigKit namespaces.
|
||||||
|
|
||||||
The intended public surface is per-input placement, illustratively an optional
|
The public surface adds an optional `Destination Path` field on `Input`, not a
|
||||||
`Destination Path` field on `Input`, not a new loading entry point or an operation
|
new loading entry point or an operation on completed results. Content-bearing
|
||||||
on completed results. Content-bearing main inputs and underlay inputs support
|
main inputs and underlay inputs support
|
||||||
the same destination model; root placement remains the default.
|
the same destination model; root placement remains the default.
|
||||||
|
|
||||||
The following behavior defines the target:
|
The following behavior defines the target:
|
||||||
@@ -120,119 +120,6 @@ or a second configuration model. The
|
|||||||
consistency constraints; [deferred scope](deferred.md) continues to govern the
|
consistency constraints; [deferred scope](deferred.md) continues to govern the
|
||||||
unrequested features above.
|
unrequested features above.
|
||||||
|
|
||||||
## Ordered implementation plan
|
|
||||||
|
|
||||||
### 1. Settle placement semantics and the public contract
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
Record the significant assembly decision in an ADR. Review compatibility under
|
|
||||||
the release policy, including exported struct changes and unchanged zero-value
|
|
||||||
behavior. Keep unimplemented claims in the roadmap; update canonical contracts
|
|
||||||
when implementation lands. Do not turn unrelated deferred features into work.
|
|
||||||
|
|
||||||
Completion: selected semantics cover the request's public acceptance scenarios
|
|
||||||
and a simple consumer as well as PromptKit's multi-collection workflow.
|
|
||||||
|
|
||||||
### 2. Carry destinations through acquisition and imports
|
|
||||||
|
|
||||||
Thread the selected destination through root-to-engine conversion and private
|
|
||||||
load requests. Preserve its ownership and semantic key representation. Separate
|
|
||||||
source-local directive processing from application placement: extract directives
|
|
||||||
at their original root, inherit placement through traversal, and place application
|
|
||||||
content before checks and composition that require effective paths.
|
|
||||||
|
|
||||||
Make version protection destination-aware for underlay roots and imported
|
|
||||||
fragments, preserving the main check's lifecycle position. Ensure diagnostics
|
|
||||||
produced before final composition identify effective application paths where
|
|
||||||
available while preserving actual source coordinates. Structural directive
|
|
||||||
errors still need their genuine source-local declaration locations.
|
|
||||||
|
|
||||||
Retain repeated-source detection across the whole strict group, independent of
|
|
||||||
destination. Preserve filesystem namespace, resource contexts, and traversal
|
|
||||||
ordering. Account for destination depth and introduced nodes using existing
|
|
||||||
budgets; distinguish them from acquired source bytes and physical source count.
|
|
||||||
|
|
||||||
Completion: all content-bearing source kinds and transitive imports contribute
|
|
||||||
at the intended destination, with correct version protection and source identity.
|
|
||||||
|
|
||||||
### 3. Integrate composition, provenance, and the final lifecycle
|
|
||||||
|
|
||||||
Apply ordinary composition to placed contributions and ordinary overlay between
|
|
||||||
tiers. Retain each source application at its effective placement for history;
|
|
||||||
carry real source attribution and the selected synthetic-container convention
|
|
||||||
through origin construction. Avoid a separate merge algorithm or a mount registry.
|
|
||||||
|
|
||||||
Exercise overlapping destinations, empty mappings, and a version-only domain
|
|
||||||
override. Resolve sibling inheritance after the full precedence assembly, then
|
|
||||||
use existing defaults, typed decoding, resolution, secrets, and validation.
|
|
||||||
Check protection of the specification path through inheritance, selected
|
|
||||||
overlays, and CLI overrides as well as direct contributions.
|
|
||||||
|
|
||||||
Completion: mounted and explicitly wrapped equivalents agree on values,
|
|
||||||
conflicts, presence, and lifecycle results; physical locations remain accurate.
|
|
||||||
|
|
||||||
### 4. Complete inspection and public consumer workflows
|
|
||||||
|
|
||||||
Expose placement through the selected existing inspection surface, with detached
|
|
||||||
records. Verify effective paths throughout metadata, explanation replay, history,
|
|
||||||
rendering, and diffs. Apply the existing sensitivity rules to mounted and inherited
|
|
||||||
fields, including superseded values. Do not fabricate coordinates for wrappers
|
|
||||||
that were never written in a source file.
|
|
||||||
|
|
||||||
Demonstrate source-relative resource lookup from both resolution and completed
|
|
||||||
results, including inherited fields and lower-tier fields surviving an override.
|
|
||||||
Add executable public examples for one mounted fragment and a representative
|
|
||||||
multi-collection assembly with peer composition and an intentional override.
|
|
||||||
Applications select sources and destinations; the examples should require no
|
|
||||||
consumer-side parsing, generic merging, or provenance reconstruction.
|
|
||||||
|
|
||||||
Completion: the supported root API is sufficient for the requested end-to-end
|
|
||||||
workflow, including accurate placement and source-relative resource inspection.
|
|
||||||
|
|
||||||
### 5. Validate the full feature and update owning documentation
|
|
||||||
|
|
||||||
Use engine tests for placement mechanics and public tests for observable loading
|
|
||||||
and inspection. Map every scenario in the request's acceptance table to a test
|
|
||||||
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 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;
|
|
||||||
- inherited import destinations, source-root directives, repeated physical
|
|
||||||
sources at different destinations, and unchanged cycle/containment behavior;
|
|
||||||
- nested ordinary version fields versus actual protected-path and ancestor
|
|
||||||
claims, including mounted imported content;
|
|
||||||
- local inheritance across peers and source contexts after inheritance/overlay;
|
|
||||||
- effective diagnostic paths with real locations, callback paths, history,
|
|
||||||
rendering, diffs, and classified values protected with disposable canaries;
|
|
||||||
- equivalent content across every supported source kind, invalid loads with no
|
|
||||||
usable result, introduced depth/node limits, and detached inspection ownership.
|
|
||||||
|
|
||||||
Follow the [testing policy](../policy/testing.md): protect observable contracts
|
|
||||||
without fixing incidental wrapper allocation or helper-call sequences. Run
|
|
||||||
focused tests, then the everyday check and ownership race validation in the
|
|
||||||
[development guide](../development.md). Validate local documentation links.
|
|
||||||
No independent performance benchmark runs are required for this roadmap.
|
|
||||||
|
|
||||||
Update declaration documentation, the configuration contract, consumer guidance,
|
|
||||||
and the component overview as their behavior lands. Document how source-local
|
|
||||||
coordinates relate to effective paths and how placement is inspected. Review
|
|
||||||
release compatibility separately from publication; feature completion does not
|
|
||||||
authorize a release.
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
## Selected Design Decisions
|
## Selected Design Decisions
|
||||||
|
|
||||||
### Main-input destinations and absent inputs
|
### Main-input destinations and absent inputs
|
||||||
@@ -246,8 +133,8 @@ across its roles and preserves absence without per-fragment version checks.
|
|||||||
|
|
||||||
### Public placement inspection and synthetic ancestors
|
### Public placement inspection and synthetic ancestors
|
||||||
|
|
||||||
Expose effective placement on existing source records,
|
Expose effective placement as `SourceInfo.Destination Path` on existing source
|
||||||
illustratively `SourceInfo.Destination`, including inherited import placement.
|
records, including inherited import placement.
|
||||||
Use original source identity for introduced ancestor mappings, documenting that
|
Use original source identity for introduced ancestor mappings, documenting that
|
||||||
any root-location fallback identifies the contributing document rather than a
|
any root-location fallback identifies the contributing document rather than a
|
||||||
physically authored wrapper. Actual content keeps its real coordinates. This
|
physically authored wrapper. Actual content keeps its real coordinates. This
|
||||||
|
|||||||
319
docs/roadmap/promptkit-feature-request.md
Normal file
319
docs/roadmap/promptkit-feature-request.md
Normal file
@@ -0,0 +1,319 @@
|
|||||||
|
# PromptKit Feature Request: Configuration Input Destinations
|
||||||
|
|
||||||
|
Status: consumer feature request; not accepted or implemented.
|
||||||
|
|
||||||
|
## Requested Capability
|
||||||
|
|
||||||
|
Provide a public API through which a consumer can select a destination mapping
|
||||||
|
path for each configuration input. The input's application content contributes
|
||||||
|
beneath that path while retaining ConfigKit's normal composition, precedence,
|
||||||
|
inheritance, validation, diagnostics, and inspection behavior.
|
||||||
|
|
||||||
|
PromptKit needs this capability for its proposal 3, **Collections With Mounted
|
||||||
|
Configuration Fragments**, recorded in PromptKit's
|
||||||
|
`docs/roadmap/configuration-collections-mounted-fragments.md`. This request
|
||||||
|
describes the public API needs and observable acceptance criteria. It does not
|
||||||
|
prescribe ConfigKit's internal design or an implementation plan.
|
||||||
|
|
||||||
|
The reviewed public baseline is ConfigKit v0.7.1. The current
|
||||||
|
[layered-loading contract](../config.md#layered-loading) lets consumers choose
|
||||||
|
sources, import policy, filesystem context, and precedence groups, but does not
|
||||||
|
provide an input destination. Existing behavior remains authoritative until an
|
||||||
|
extension is adopted.
|
||||||
|
|
||||||
|
## Consumer Problem
|
||||||
|
|
||||||
|
PromptKit applications assemble independently maintained collections of prompts,
|
||||||
|
inference profiles, and backends. Collections can contain identical local names,
|
||||||
|
such as `summarize.alerts`, without identifying the same resource. PromptKit wants
|
||||||
|
an effective configuration organized by collection, while letting authors omit
|
||||||
|
repeated collection and resource-container wrappers from individual files.
|
||||||
|
|
||||||
|
A file selected from a collection's `prompts` directory would contain:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
summarize.alerts:
|
||||||
|
version: "1"
|
||||||
|
default_profile: provider/brief
|
||||||
|
messages:
|
||||||
|
- role: user
|
||||||
|
content: Summarize the weather alerts.
|
||||||
|
output:
|
||||||
|
format: text
|
||||||
|
validation_mode: none
|
||||||
|
```
|
||||||
|
|
||||||
|
Given destination `[collections, weatherreporter, prompts]`, its contribution
|
||||||
|
would appear in the final application configuration as:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
collections:
|
||||||
|
weatherreporter:
|
||||||
|
prompts:
|
||||||
|
summarize.alerts:
|
||||||
|
version: "1"
|
||||||
|
default_profile: provider/brief
|
||||||
|
messages:
|
||||||
|
- role: user
|
||||||
|
content: Summarize the weather alerts.
|
||||||
|
output:
|
||||||
|
format: text
|
||||||
|
validation_mode: none
|
||||||
|
```
|
||||||
|
|
||||||
|
Another collection can contribute `summarize.alerts` beneath
|
||||||
|
`[collections, homewatch, prompts]` without conflicting. After final handoff,
|
||||||
|
PromptKit interprets these as `weatherreporter/summarize.alerts` and
|
||||||
|
`homewatch/summarize.alerts`. The profile reference is illustrative and must be
|
||||||
|
supplied separately by the application configuration.
|
||||||
|
|
||||||
|
PromptKit will support one installed definition per prompt. Its optional flat
|
||||||
|
`version` is ordinary domain metadata, not a merge identity. This request does
|
||||||
|
not need identified-record sequences, sequence-root documents, or a custom
|
||||||
|
merge policy.
|
||||||
|
|
||||||
|
Authors could write the complete wrappers today, but that repeats assembly
|
||||||
|
details in every fragment. Consumer-side parsing and wrapping would put generic
|
||||||
|
source processing back into PromptKit and complicate source attribution.
|
||||||
|
PromptKit instead wants to select sources and destinations, then receive one
|
||||||
|
final configuration through ConfigKit's supported loading lifecycle.
|
||||||
|
|
||||||
|
## Minimum Public API
|
||||||
|
|
||||||
|
### Per-Input Destination
|
||||||
|
|
||||||
|
Allow a destination to be attached to each `Input` passed to `LoadLayered`.
|
||||||
|
One possible public spelling is an optional `Destination Path` field on `Input`.
|
||||||
|
The name and exact signature are suggestions; equivalent public API designs
|
||||||
|
are welcome.
|
||||||
|
|
||||||
|
Illustrative consumer code using the proposed field, which does not exist in
|
||||||
|
v0.7.1:
|
||||||
|
|
||||||
|
```go
|
||||||
|
promptInput := configkit.Input{
|
||||||
|
Source: configkit.File("/usr/local/share/collections/weatherreporter/prompts/alerts.yml"),
|
||||||
|
Destination: configkit.Keys("collections", "weatherreporter", "prompts"),
|
||||||
|
}
|
||||||
|
|
||||||
|
peers := configkit.Underlay{
|
||||||
|
Inputs: []configkit.Input{promptInput},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The consumer would include `peers` in its existing `LayeredOptions` and invoke
|
||||||
|
`LoadLayered` with its normal root main input and application `Definition`.
|
||||||
|
This is a partial API sketch, not an executable example or a proposed new
|
||||||
|
loading entry point. A single public layered load is sufficient for PromptKit;
|
||||||
|
it does not require a separate mounting operation on completed results.
|
||||||
|
|
||||||
|
The API must let the consumer:
|
||||||
|
|
||||||
|
- Express a destination relative to the application configuration root using
|
||||||
|
literal mapping-key segments. Dots, slashes, and numeric-looking text inside
|
||||||
|
a key are not implicit path separators or array indexes. PromptKit's namespace
|
||||||
|
grammar remains its own domain rule.
|
||||||
|
- Omit the destination to retain existing root placement. An explicitly empty
|
||||||
|
destination should have the same meaning. Mapping destinations are sufficient;
|
||||||
|
sequence-index destinations are not needed by this request.
|
||||||
|
- Assign different destinations to inputs in the same strict composition group,
|
||||||
|
and assign the same destination to inputs in separate precedence groups.
|
||||||
|
- Use the destination with existing content-bearing source kinds: host files,
|
||||||
|
native filesystem files, bytes, readers, and mapping sources, subject to their
|
||||||
|
existing acquisition and ownership contracts.
|
||||||
|
- Retain the existing import opt-in and filesystem context independently of the
|
||||||
|
destination. A configuration destination is not a filesystem root or base
|
||||||
|
directory.
|
||||||
|
|
||||||
|
PromptKit can continue to enumerate an explicitly selected directory and attach
|
||||||
|
the same destination to its returned inputs. ConfigKit does not need a new
|
||||||
|
directory scanner, namespace registry, filename convention, or PromptKit schema.
|
||||||
|
The namespace comes from the application's assembly declaration, not from an
|
||||||
|
implicit interpretation of a directory basename.
|
||||||
|
|
||||||
|
### Representative Assembly
|
||||||
|
|
||||||
|
These are application choices, not ConfigKit-specific reserved paths:
|
||||||
|
|
||||||
|
| Selected inputs | Destination key segments |
|
||||||
|
| --- | --- |
|
||||||
|
| Application main document | Root |
|
||||||
|
| `weatherreporter/collection.yml` | `collections`, `weatherreporter` |
|
||||||
|
| YAML files under `weatherreporter/prompts` | `collections`, `weatherreporter`, `prompts` |
|
||||||
|
| YAML files under `homewatch/prompts` | `collections`, `homewatch`, `prompts` |
|
||||||
|
| YAML files under `provider/profiles` | `collections`, `provider`, `profiles` |
|
||||||
|
| YAML files under `provider/backends` | `collections`, `provider`, `backends` |
|
||||||
|
|
||||||
|
Peer collection contributions belong to a single strict underlay group when the
|
||||||
|
application wants conflict detection among them. Intentional operator overrides
|
||||||
|
use later groups or main. Destination selection must not establish precedence
|
||||||
|
or make source traversal order authorize replacement.
|
||||||
|
|
||||||
|
## Required Observable Behavior
|
||||||
|
|
||||||
|
### Composition And Precedence
|
||||||
|
|
||||||
|
Mounted and explicitly wrapped contributions must have equivalent application
|
||||||
|
values and conflict behavior at their effective destinations. Actual source
|
||||||
|
locations naturally differ and must remain accurate.
|
||||||
|
|
||||||
|
Retain the [strict composition](../config.md#strict-document-composition) and
|
||||||
|
[layering](../config.md#layered-loading) rules:
|
||||||
|
|
||||||
|
- Disjoint mapping entries at the same destination combine.
|
||||||
|
- Overlapping non-mapping values within a strict group conflict, including equal
|
||||||
|
scalars, nulls, and sequences. Different destinations do not collide merely
|
||||||
|
because the source documents share a local key.
|
||||||
|
- Later precedence layers recursively override mappings and replace other
|
||||||
|
values. A strict conflict cannot be repaired by an upper layer.
|
||||||
|
- Empty mappings do not clear lower definitions; ordinary arrays remain atomic.
|
||||||
|
In particular, `messages` does not acquire sequence-merging behavior.
|
||||||
|
- Overlapping destination paths and contributions at their ancestors follow
|
||||||
|
those same rules. No namespace-level uniqueness restriction is requested.
|
||||||
|
|
||||||
|
Changing only a prompt's `version` in a later layer changes that field while
|
||||||
|
retaining omitted lower-layer fields. ConfigKit must not treat a domain version
|
||||||
|
label as a request to replace an entire definition.
|
||||||
|
|
||||||
|
### Imports And Existing Structural Directives
|
||||||
|
|
||||||
|
An input with imports enabled must be able to use its existing source-root
|
||||||
|
`configkit.imports` directive while contributing application data at a nested
|
||||||
|
destination. The directive remains structural configuration, not an application
|
||||||
|
field below that destination.
|
||||||
|
|
||||||
|
For the minimum API, imports inherit their importing input's destination,
|
||||||
|
including transitive imports. Import paths continue to resolve relative to
|
||||||
|
their declaring source's filesystem context. A mounted document must not send
|
||||||
|
its imported application fields back to the configuration root accidentally.
|
||||||
|
|
||||||
|
Existing opt-in, containment, missing-input, cycle, and repeated-source behavior
|
||||||
|
must remain applicable. A different destination is not a request to bypass the
|
||||||
|
current rejection of a repeated physical source within a strict group.
|
||||||
|
|
||||||
|
Sibling `extends` must resolve against mappings at their effective destinations.
|
||||||
|
For example, two independently supplied profile fragments mounted beneath the
|
||||||
|
same collection's `profiles` mapping can establish `extends: brief` once they
|
||||||
|
compose. Inheritance remains ConfigKit-owned; PromptKit does not perform another
|
||||||
|
relationship-resolution pass.
|
||||||
|
|
||||||
|
### Protected Specification Paths
|
||||||
|
|
||||||
|
The distinction between source-local field names and effective application
|
||||||
|
paths is essential. PromptKit's main document will declare `version: 1` at the
|
||||||
|
configuration root. A separate collection metadata file can contain:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: "2.4.0"
|
||||||
|
```
|
||||||
|
|
||||||
|
Mounted at `[collections, weatherreporter]`, that field is an ordinary collection
|
||||||
|
release label. It must not be rejected as an attempt to contribute the protected
|
||||||
|
root specification field. The same applies to a prompt's nested optional
|
||||||
|
version. Only the main-owned specification declaration uses the application's
|
||||||
|
configured [VersionRule](../config.md#application-schema-versions).
|
||||||
|
|
||||||
|
Conversely, placement must not permit an underlay or imported fragment to claim
|
||||||
|
or replace the actual protected specification path or an ancestor that would
|
||||||
|
replace it. The public contract must define protection in terms of effective
|
||||||
|
application paths, rather than reserving the spelling `version` in every source.
|
||||||
|
Protection must remain valid with imports, inheritance, overlays, and explicit
|
||||||
|
CLI overrides.
|
||||||
|
|
||||||
|
PromptKit needs one main-owned specification check with the existing lifecycle.
|
||||||
|
It does not need main mounted away from the root, integer-to-string conversion
|
||||||
|
for every nested `version`, or separate compatibility checks for every fragment.
|
||||||
|
|
||||||
|
### Typed Loading, Diagnostics, And Inspection
|
||||||
|
|
||||||
|
The destination must be visible consistently through the ordinary public
|
||||||
|
loading and inspection surface:
|
||||||
|
|
||||||
|
- Final typed configuration and application callbacks use effective destination
|
||||||
|
paths. Defaults, resolution, and validation retain the existing single-load
|
||||||
|
lifecycle; fragments are not independently validated as whole applications.
|
||||||
|
- Metadata and presence queries distinguish omission, explicit null, and other
|
||||||
|
explicit values at the mounted paths.
|
||||||
|
- Diagnostics identify the effective conflicting or invalid path and the real
|
||||||
|
contributing source locations. Consumers can determine which source and
|
||||||
|
placement produced a value without recreating that relationship themselves.
|
||||||
|
- Effective rendering, explanations, history, and configuration comparison agree
|
||||||
|
with the final configuration. Existing sensitivity and disclosure rules apply
|
||||||
|
to mounted fields, including application path-based secret classification.
|
||||||
|
- Unsupported destination forms and destination-related loading failures use
|
||||||
|
the normal structured error boundary. Exact new diagnostic codes, if needed,
|
||||||
|
are for ConfigKit to define.
|
||||||
|
|
||||||
|
PromptKit does not require a separate mount registry or new inspection facade.
|
||||||
|
Existing inspection APIs are sufficient if they expose accurate effective paths,
|
||||||
|
source attribution, and placement information. ConfigKit should document how
|
||||||
|
source-local locations relate to effective paths.
|
||||||
|
|
||||||
|
### Source-Relative Resources And Lifecycle
|
||||||
|
|
||||||
|
For a mounted field such as `content_file: ./summary.md`, obtaining its effective
|
||||||
|
origin and calling `Result.SourceContext` or `Resolution.SourceContext` must
|
||||||
|
still identify the declaring source's filesystem and base directory. The same
|
||||||
|
holds when that field survives an override or is inherited into another mapping.
|
||||||
|
Its configuration destination must not change the meaning of the relative file
|
||||||
|
reference.
|
||||||
|
|
||||||
|
Retain existing source ownership, load completion, result lifetime, containment,
|
||||||
|
and resource-access behavior. Destinations must participate in documented load
|
||||||
|
limits without creating a way to bypass them; this request does not prescribe
|
||||||
|
new limit values or their accounting machinery.
|
||||||
|
|
||||||
|
## Optional Follow-Ups, Not Prerequisites
|
||||||
|
|
||||||
|
**Import destinations in YAML.** A destination on an import directive could let
|
||||||
|
publishers describe assembly in configuration rather than Go. Proposal 3
|
||||||
|
recommends destinations relative to the importing document's destination, with
|
||||||
|
omission retaining that destination. This is useful, but per-input placement
|
||||||
|
through the public API is sufficient for initial PromptKit adoption. No new
|
||||||
|
directive spelling is selected by this request.
|
||||||
|
|
||||||
|
**Independent specification headers.** A collection entry document might later
|
||||||
|
declare its own supported specification version. That needs a distinct contract
|
||||||
|
for checking the header and determining its role in the composed configuration.
|
||||||
|
Mounting collection release metadata does not supply this capability. Keep it a
|
||||||
|
separate request if PromptKit decides it is necessary.
|
||||||
|
|
||||||
|
**Cross-collection inheritance.** Nested collection profiles are not immediate
|
||||||
|
siblings across collections. Current sibling inheritance remains sufficient for
|
||||||
|
the initial proposal, with authored definitions flattened where necessary.
|
||||||
|
Generic cross-path inheritance could be considered separately if consumer needs
|
||||||
|
justify revisiting the [deferred scope](deferred.md). Mounting must not silently
|
||||||
|
reinterpret `extends: provider/brief` as a cross-collection reference.
|
||||||
|
|
||||||
|
PromptKit also does not request collection installation, automatic directory
|
||||||
|
discovery, remote fetching, namespace ownership enforcement, dependency solving,
|
||||||
|
live reload, filename-derived identity, or arbitrary document transformations.
|
||||||
|
Its qualified resource IDs, optional prompt version semantics, collection
|
||||||
|
inventory, and execution APIs remain PromptKit responsibilities.
|
||||||
|
|
||||||
|
## Public Acceptance Scenarios
|
||||||
|
|
||||||
|
Evaluate the extension through supported public loading and inspection APIs:
|
||||||
|
|
||||||
|
| Scenario | Expected consumer-visible result |
|
||||||
|
| --- | --- |
|
||||||
|
| Destination omitted or empty | Existing root-placement behavior |
|
||||||
|
| Same fragment shape mounted under two distinct collection keys from independent sources | Two separate effective resources |
|
||||||
|
| Disjoint inputs at the same destination in one group | Mapping contributions combine |
|
||||||
|
| Equal or unequal overlapping scalar fields in one group | Structured composition conflict with both source locations |
|
||||||
|
| Same destination across deliberate precedence tiers | Existing recursive overlay behavior |
|
||||||
|
| Version-only prompt override | Label changes; omitted prompt body fields survive |
|
||||||
|
| Nested mounted import without a destination directive | Imported fields contribute at the inherited destination |
|
||||||
|
| Local profile inheritance across mounted peer fragments | Parent resolves at the effective sibling scope |
|
||||||
|
| Collection metadata containing `version` mounted below root | Ordinary nested field, independent of root VersionRule |
|
||||||
|
| Mounted/imported contribution actually targeting the protected version path | Rejected under version ownership rules |
|
||||||
|
| Mounted field using source-relative content, including inheritance | Original declaring resource context remains available |
|
||||||
|
| Mounted explicit null and omitted field | Distinct effective presence information |
|
||||||
|
| Mounted validation error or secret field | Effective paths, physical locations, and existing disclosure rules agree |
|
||||||
|
| File, native filesystem, byte, reader, or mapping input with equivalent content | Equivalent application values, subject to existing source contracts |
|
||||||
|
| Unsupported destination or failed load | Normal structured failure, no usable partial result |
|
||||||
|
|
||||||
|
The minimum usable outcome is a consumer that selects collection sources and
|
||||||
|
destinations, performs one ordinary layered load, and receives final typed
|
||||||
|
configuration with reliable diagnostics and inspection. It should need no
|
||||||
|
consumer-side source rewriting, generic merging, or provenance reconstruction.
|
||||||
Reference in New Issue
Block a user