Prepare sequence registration preflight

This commit is contained in:
2026-10-16 15:19:32 +00:00
parent 90c2d7e409
commit ff212885c4
6 changed files with 268 additions and 1 deletions

View File

@@ -0,0 +1,73 @@
# ADR 0014: Place and Compose Sequence Items Explicitly
## Status
Accepted. Implementation status and sequencing are tracked in the
[sequence composition implementation plan](../roadmap/implementation.md).
## Date
2026-10-16
## Context
ConfigKit strictly composes independent documents by recursively combining
mappings and rejecting other overlapping values. This makes two independently
authored sequence fragments conflict, even when their records are distinct.
Precedence assembly has a different purpose: a higher-priority present sequence
replaces the lower-priority sequence as one value. Those existing rules are
predictable, but they do not express the separate operation of collecting
independent records while rejecting duplicate identities.
Likewise, mapping destinations place a source beneath literal mapping keys, but
there is no explicit way to state that a source mapping represents one item in a
sequence. Inferring that intent from document shape or fields would make source
meaning implicit and change existing placement behavior.
## Decision
Keep mapping placement as the zero-value behavior and add an explicit item
placement choice for a source whose mapping should become one element at a
non-root sequence destination. Item placement provides structure only; it does
not infer or synthesize identity values.
Allow a definition to register literal mapping paths and one literal identity
field for sequences at those paths. Within each strict composition tier, a
registered sequence accepts mapping records with a present string identity,
appends distinct records in contribution order, and rejects repeated exact
identity strings. Identical registrations coalesce; conflicting identity fields
for the same path are invalid. Registration does not recursively select paths
inside sequence records.
Keep precedence assembly unchanged. A present higher-priority sequence replaces
the lower-priority value wholesale, including at a registered path. Registration
changes strict composition only; it does not turn precedence into append or
identity-based merging.
This decision preserves ConfigKit's distinction between independent
same-priority contributions and intentional precedence. Explicit source
placement and definition-owned composition policy make the two required choices
visible while keeping the existing zero-value load behavior.
## Alternatives Considered
- **Infer item placement from a source mapping or identity field.** Shape-based
inference would make ordinary mapping placement depend on document contents
and would leave the intended destination ambiguous.
- **Append all overlapping sequences during strict composition.** This would
change existing conflict semantics at unregistered paths and would not detect
duplicate records.
- **Merge matching records recursively by identity.** This would add a second
recursive merge rule with different conflict and precedence behavior from
ConfigKit's existing mapping composition and overlay operations.
- **Use identity to merge sequences across precedence tiers.** This would
change established whole-value replacement semantics and conflate strict
composition with precedence.
## Consequences
Consumers can explicitly place mappings as sequence items and opt selected
sequences into duplicate-rejecting strict composition. Unregistered sequences
retain their current strict-conflict behavior, and higher-priority sequences
continue to replace lower-priority ones. The implementation plan owns the exact
API, YAML syntax, diagnostics, and implementation status.

View File

@@ -213,6 +213,24 @@ Scope: one ADR and engine option normalization; no new public fields yet.
Validation: focused option tests and `./scripts/check.sh`. Completion: existing
loads remain unchanged, with only private registered-policy input newly accepted.
Completion evidence: added Accepted ADR 0014 and private engine registration
normalization. Ordinary and layered entry points compile/coalesce policy and
reject invalid registrations before source reads, then carry the compiled policy
through the load request while clearing raw registration slices from internal
handoffs. No public API or composition behavior was added. Focused coverage
checks duplicate/conflicting definitions, empty identity names, numeric and
escaped literal keys, invalid explicit indexes, unused/root registrations,
zero-option behavior, and reader preservation on preflight failure. These checks
passed with Go `go1.26.9 linux/amd64`:
- `GOTOOLCHAIN=local GOPROXY=off go test ./internal/engine -run 'SequenceRegistration' -count=1`
- `GOTOOLCHAIN=local ./scripts/check.sh`
- `git diff --check`
The compiled registration policy is intentionally not consumed by composition
until the next implementation unit. No environmental limitation affected
validation; checks ran on Linux/amd64.
## Stage 2 — Implement registered strict sequence validation and assembly
Scope: `internal/engine/compose.go` and focused composition tests.