Expose sequence placement controls in the public API
This commit is contained in:
@@ -67,13 +67,18 @@ ID `source-1`; enabled imports continue in depth-first order as `source-2` onwar
|
||||
contributes no source, and continues through defaults, decode, and projection. A
|
||||
missing file remains an error; it is never interpreted as no input.
|
||||
|
||||
The current `Options` boundary accepts a defaults factory, `VersionRule`, resolver,
|
||||
semantic validator, explicit path and glob imports, one selected overlay, and
|
||||
filesystem context. It also accepts explicit CLI override records, static secret
|
||||
tags, and a dynamic path predicate. `NoSource` rejects imports, active overlays,
|
||||
and filesystem context as invalid combinations but accepts overrides. Input
|
||||
containing a reserved `configkit` mapping key is rejected while imports are
|
||||
disabled.
|
||||
`Options` accepts the application definition, ordinary-source `Destination` and
|
||||
`PlacementMode`, explicit path and glob imports, one selected overlay, filesystem
|
||||
context, explicit CLI overrides, and shared source-version controls. The definition
|
||||
may register strict sequence composition paths through
|
||||
`SequenceCompositions`. Its zero-valued placement mode places the source mapping
|
||||
at the destination; `sequence-item` explicitly wraps the mapping as one item at a
|
||||
non-root destination. Unknown modes, invalid destinations, and invalid or
|
||||
conflicting sequence registrations fail before source acquisition. Overlay and
|
||||
CLI coordinates remain rooted at the application root. `NoSource` rejects
|
||||
imports, active overlays, and filesystem context as invalid combinations but
|
||||
accepts overrides. Input containing a reserved `configkit` mapping key is rejected
|
||||
while imports are disabled.
|
||||
|
||||
Every source, options, schema, version, defaults, decode, resolution, or validation
|
||||
failure returns a nil result and a `*LoadError`. Successful results contain caller-owned `Config`, detached
|
||||
@@ -176,12 +181,21 @@ follow the same strict composition within a tier and recursive precedence
|
||||
behavior described above. A selected overlay and CLI overrides remain rooted at
|
||||
the application root and are not moved beneath the main input's destination.
|
||||
|
||||
`SourceInfo.Destination` reports the placement for each acquired input source,
|
||||
including imports. Placement does not change source IDs, acquisition identity,
|
||||
physical source locations, or passive resource contexts. Introduced ancestor
|
||||
mappings use the contributing document's root location as a source fallback;
|
||||
authored content retains its original source coordinates. Returned source
|
||||
records are detached copies.
|
||||
`SourceInfo.Destination` reports each acquired source's effective mapping or
|
||||
sequence-container path, including imports. `PlacementMode` reports how that
|
||||
source was placed; mapping is the zero value, and CLI/overlay sources report
|
||||
mapping unless item placement was applied. `DestinationUnresolved` is true only
|
||||
when an enclosing item index needed to name the source's destination has not yet
|
||||
been assigned. In that case `Destination` reports the nearest resolved enclosing
|
||||
collection container and omits the unresolved local suffix. A source's own item
|
||||
placement still has an exact destination at its sequence container. Completed
|
||||
loads project nested source destinations through their owning items. Callback and
|
||||
failed-load snapshots preserve the evidence available at that point; a fallback
|
||||
snapshot remains unresolved, while a later exact snapshot is false. Returned
|
||||
source records and paths are detached. Placement does not change source IDs,
|
||||
acquisition identity, physical source locations, or passive resource contexts.
|
||||
Introduced ancestor mappings use the contributing document's root location as a
|
||||
source fallback; authored content retains its original source coordinates.
|
||||
|
||||
The maintained [layered consumer example](consumers/README.md#native-filesystem-and-layered-input)
|
||||
shows a main host file, two underlay tiers, embedded defaults, a mapping source,
|
||||
@@ -744,12 +758,39 @@ Application defaults do not participate in this operation.
|
||||
| Mapping | Mapping | Recurse by mapping key |
|
||||
| Any other pair of present nodes | Any other pair of present nodes | `compose.conflict` |
|
||||
|
||||
Every non-mapping overlap is a conflict, even when values are equal. Nulls and
|
||||
sequences are present atomic values, so they also conflict when repeated; sequences
|
||||
are never joined by index. Disjoint entries under shared mappings compose, making
|
||||
Every non-mapping overlap is a conflict, even when values are equal, except for
|
||||
sequence/sequence contributions at a registered sequence-composition path. Nulls
|
||||
remain atomic conflicts. Unregistered sequences conflict when repeated and are
|
||||
never joined by index. Disjoint entries under shared mappings compose, making
|
||||
stable keyed mappings the natural representation for independently contributed
|
||||
entries.
|
||||
|
||||
`Definition.SequenceCompositions` registers literal mapping paths and one literal
|
||||
`IdentityField` for sequences that should compose independently authored records.
|
||||
Registration paths follow input-destination key rules: parsed numeric tokens are
|
||||
literal mapping keys, explicit index segments and reserved `configkit` or
|
||||
mapping-valued `extends` segments are invalid, and the root registration is
|
||||
harmless and unused. The identity field is one literal string key; neither the
|
||||
field name nor identity strings are normalized.
|
||||
At each registered path, every actual sequence contribution in a strict tier is
|
||||
validated, including a singleton contribution: each record must be a mapping with
|
||||
a present string identity field. Distinct exact identity strings append in source
|
||||
and list order; duplicate identities conflict even if the records are otherwise
|
||||
equal or disjoint. Empty identity strings are valid. Malformed records produce
|
||||
`compose.invalid`; duplicate identities produce `compose.conflict`, with the
|
||||
sequence container and source locations identifying a duplicate without exposing
|
||||
identity values. Missing paths and non-sequence values do not fail by themselves.
|
||||
Identical registrations coalesce; conflicting registrations at one path and
|
||||
invalid registration paths produce `options.invalid`. Unused and root registrations
|
||||
are allowed and have no effect.
|
||||
|
||||
Registration changes strict composition only. Each underlay group and the main
|
||||
tier has independent duplicate-identity state. Precedence assembly is unchanged:
|
||||
a present higher-priority sequence replaces the lower sequence as one value,
|
||||
including at a registered path. Overlays, CLI overrides, defaults, inheritance,
|
||||
and application resolution do not run the registered identity check. The accepted
|
||||
rationale is recorded in [ADR 0014](adr/0014-sequence-placement-and-composition.md).
|
||||
|
||||
An empty mapping contributes no child definitions. Two empty mappings compose, and
|
||||
an empty mapping neither clears nor conflicts with another mapping's children.
|
||||
Shared mapping containers retain all contributing value locations as their composite
|
||||
@@ -889,8 +930,9 @@ Each path or glob declaration may include `placement: mapping` or
|
||||
including every match of a glob; placement is not inherited. Sequence-item
|
||||
placement requires a nonempty effective destination and wraps the imported
|
||||
mapping as one element of a sequence there. It does not split source sequences
|
||||
or enable sequence accumulation: overlapping sequences still follow the strict
|
||||
composition rules above.
|
||||
or infer identity fields. Repeated sequences still conflict unless their path is
|
||||
registered through `Definition.SequenceCompositions`; registration does not
|
||||
change placement or precedence behavior.
|
||||
|
||||
An item import first opens a local mapping scope. Its body and ordinary helper
|
||||
imports compose within that record. An omitted helper destination or
|
||||
|
||||
@@ -170,6 +170,13 @@ Tier precedence is explicit; traversal order within a tier establishes stable
|
||||
reporting, not permission to override. The distinction and its rationale are
|
||||
recorded in [ADR 0001](../adr/0001-separate-composition-and-overlay.md).
|
||||
|
||||
At definition-registered sequence paths, strict composition appends mapping
|
||||
records with distinct present string identities and rejects duplicates.
|
||||
Placement and registration are explicit source and definition controls; they do
|
||||
not change precedence replacement. The [configuration contract](../config.md#strict-document-composition)
|
||||
defines the behavior, and [ADR 0014](../adr/0014-sequence-placement-and-composition.md)
|
||||
records the decision.
|
||||
|
||||
The main document and its imports form a strictly composed tier. Explicit
|
||||
underlay groups compose strictly within each group, then combine recursively
|
||||
from lowest to highest beneath the main tier. Source acquisition kind does not
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Implementation Plan: Sequence Placement and Composition
|
||||
|
||||
Status: implementation in progress; stages 1–10 completed.
|
||||
Status: implementation in progress; stages 1–11 completed.
|
||||
|
||||
## Purpose and authority
|
||||
|
||||
@@ -658,6 +658,25 @@ Validation: focused facade tests,
|
||||
Completion: both public entry points expose the complete feature with the same
|
||||
composition rules and independently owned evidence.
|
||||
|
||||
Completion evidence: the root facade now exposes sequence registrations,
|
||||
ordinary and layered placement controls, and detached placement-mode and
|
||||
destination-resolution source evidence. Public integration coverage exercises
|
||||
ordinary/layered placement, strict registration with authored and glob-imported
|
||||
items, shifted origins and resource contexts, option preflight, early and
|
||||
post-placement failure snapshots, nested fallback containers, registration and
|
||||
snapshot ownership, and zero-value mapping behavior. The existing resolver
|
||||
callback runs after item projection, so its source snapshots are exact; the
|
||||
unresolved helper fallback is observable on early failure. No acquisition-time
|
||||
callback exposes `SourceInfo`, and no additional callback lifecycle was added.
|
||||
These checks passed with Go `go1.26.9 linux/amd64`:
|
||||
|
||||
- `GOTOOLCHAIN=local GOPROXY=off go test . -run 'TestPublicFacadeBoundary|TestDependencyImportBoundary' -count=1`
|
||||
- `GOTOOLCHAIN=local GOPROXY=off go test -race ./...`
|
||||
- `GOTOOLCHAIN=local GOPROXY=off ./scripts/check.sh`
|
||||
- `git diff --check`
|
||||
|
||||
No environmental limitation affected validation; checks ran on Linux/amd64.
|
||||
|
||||
## Stage 12 — Close cross-cutting regression and limit gaps
|
||||
|
||||
Scope: risks that require the assembled feature, not duplicate mechanism tests.
|
||||
|
||||
Reference in New Issue
Block a user