# Sequence Identity And Combination Roadmap Status: settled feature roadmap; implementation is specified in the [staged implementation plan](implementation.md). This document defines the targeted end state, not an implemented contract. The implementation plan owns execution order, exact Go names and signatures, bookkeeping, and validation. ## Purpose And Scope Allow configuration authors to assemble collections from independently authored records, declare identity in configuration, and progressively extend a baseline collection through higher layers. Authors can replace the entire collection, append distinct records, or replace complete records by identity while retaining unmatched records. Sibling inheritance uses the same sequence operations and identity-based defaults. Within an identified sequence, a record can explicitly inherit settings from another record in that sequence while keeping its own identity. The motivating use case is a prompt catalog whose source-backed baseline supplies records and whose application or installation layers add or supersede records. Applications can optionally impose identity constraints that configuration must respect and that hold in the final loaded configuration. These constraints can cover exact destinations or collections beneath dynamically named mapping keys, without requiring the application to discover those names before loading. The feature covers ordinary and layered loading, imported items, inline sequences, selected overlays, and sibling inheritance. Typed defaults, CLI assignments, and application resolution retain their own combination semantics; CLI application moves later in the loading lifecycle. This scope is narrower than the deferred [identified-record sequences proposal](future.md#1-identified-record-sequences). Automatic recursive merging of matching records remains outside this scope; explicit inheritance between distinct records is included. The initial declaration surface is `configkit.sequences`; `key` and `mode` shorthand on imports is deferred. Application lists remain ordinary YAML sequences without control wrappers. Unkeyed sequence concatenation is outside this feature. ## Current Baseline And Required Changes The [import contract](../config.md#explicit-imports) owns existing selectors, destinations, placement, and ordering. `placement: sequence-item` already places each selected source mapping as one item at its effective destination. Item-local helper imports can contribute fields before placement. The [composition contract](../config.md#strict-document-composition), [layered-loading contract](../config.md#layered-loading), and [inheritance contract](../config.md#sibling-inheritance) describe the implemented baseline: | Area | Current behavior | Target behavior | | --- | --- | --- | | Identity declaration | `Definition.SequenceCompositions` registers one literal string field at each registered mapping path. | YAML collection declarations and optional authoritative application registrations support field sets and scalar identity components. | | Application registration destinations | Registrations select exact literal mapping paths. | Exact and structural selectors can impose identity beneath arbitrary mapping keys, independently at each matched destination. | | Strict composition | Registered sequences append distinct string identities and reject duplicates; repeated unregistered sequences conflict. | Collections with effective identity append distinct records and reject duplicates. Applicable lower-tier identity is available before composing higher-tier peers. Unidentified sequences retain strict-conflict behavior. | | Source precedence and selected overlays | A present higher sequence replaces the lower sequence wholesale. | Collection policy selects `replace`, `append`, or `upsert`; overlays can declare policy for inline sequences. | | Sibling inheritance | An inheriting mapping recursively overlays its resolved parent; supplied sequences replace wholesale. | Mappings retain recursive combination, while sequences use destination policy and the same three operations. | | Sequence-member inheritance | A sequence element has no sibling scope for its own inheritance relationship. | An identified sequence provides a sibling scope: a record can inherit from one record in the same sequence, selected by complete identity. | | CLI overrides | Apply before inheritance and typed defaults/decoding. | Apply after inheritance and typed defaults/decoding, before application resolution. | | Identity enforcement | Registration governs strict sequence composition. | Structural identity checks cover identified combinations; application registrations additionally constrain final effective sequences. | Source-backed underlays participate in source assembly. `Definition.Defaults` provides typed defaults later; extending source combination does not turn typed default lists into source underlays. ## Collection Declarations Use a source-root `configkit.sequences` block containing collection declarations. Each entry identifies a `destination` and may declare `key`, `mode`, or both. Identity and mode can be supplied independently. This form serves imported items, inline records, ordinary mapping imports, and inline sequences in selected overlays. ```yaml configkit: sequences: - destination: [prompts] key: [namespace, id] mode: append imports: - dir: prompts pattern: '*.yaml' destination: [prompts] placement: sequence-item ``` Each selected file contributes a record such as: ```yaml namespace: support id: welcome text: Welcome ``` Here append retains a lower-layer collection and adds distinct higher-layer records. Identity and combination controls belong to the collection declaration, so imported and inline contributions share one policy surface. ### Destinations And Scope `destination` uses the existing sequence of literal mapping keys. Resolve it relative to the declaring source's placement: a fragment mounted under `catalog` can declare `[prompts]` locally. A sequence-item source can declare a nested collection within its own item without referring to an eventual numeric index. Preserve source and item-local scope boundaries. A collection's scope is its resolved destination within its composition scope. Resolve relative destinations before reconciling declarations. Different imported items retain separate scopes for their nested collections. A declaration governs all contributions to its collection in the tier, including imported and inline records; it does not govern only records in the declaring file. Gather declarations before composing the relevant scope so their effect does not depend on which contribution is assembled first. Retain applicable controls through source precedence and inheritance, then keep them out of application decoding. Sequence declarations are independent of filesystem import enablement. Selected overlays may contain `configkit.sequences`, extending the current blanket prohibition on overlay `configkit` declarations. This does not enable imports in overlays. ### Overlay Authoring For an existing sequence `[foo, bar]`, an overlay can replace `foo` in full: ```yaml configkit: sequences: - destination: [prompts] key: id mode: upsert prompts: - id: foo text: Revised definition ``` The result is `[foo*, bar]`. The explicit upsert mode can be omitted when no different explicit mode applies from a lower tier: effective identity then selects upsert. To add a distinct record instead: ```yaml configkit: sequences: - destination: [prompts] key: id mode: append prompts: - id: baz text: Another prompt ``` The result is `[foo, bar, baz]`. To replace the whole sequence: ```yaml configkit: sequences: - destination: [prompts] mode: replace prompts: - id: bar text: Bar definition - id: baz text: Baz definition ``` The result is `[bar, baz]`. Explicitly selecting the default operation is valid. With no applicable explicit mode, omitting this declaration selects replace for an unidentified collection and upsert for an identified one. A retained explicit mode continues to govern. ## Identity Definitions And Constraints ### Field Sets `key` accepts a string or a nonempty list of strings naming direct, literal fields in each record. A name such as `metadata.id` denotes that literal field, not a nested lookup. Treat field names as a set: remove repeated names and ignore authored order when comparing definitions. Thus `id`, `[id]`, and `[id, id]` are equivalent; `[namespace, id]`, `[id, namespace]`, and `[namespace, id, id]` are also equivalent. An empty list is invalid because it supplies no identity fields. These rules apply to both configuration declarations and application registrations. Use a consistent field order internally to construct identity tuples. Preserve component types and tuple boundaries so unstructured concatenation cannot cause otherwise distinct identities to collide. ### Scalar Components And Equality Each identified record must be a mapping with every designated identity field present. Components may be strings, numbers, booleans, or explicit null. Missing fields and mapping or sequence components are invalid. Present null differs from absence; two single-field null identities are equal. Compound identities are equal when all corresponding components are equal. Strings compare exactly, including empty strings, without trimming, case folding, or normalization. Scalar categories remain distinct: `"1"`, `1`, `true`, and null are different identities. Numbers compare by mathematical value across integer, fractional, and exponent spellings: `1`, `1.0`, and `1e0` are equal, as are `0` and `-0`. Use exact numeric normalization for identity comparison without rounding through a floating-point conversion. This does not rewrite authored values or change existing typed decoding and projection semantics. The parser's rejection of non-finite numeric forms remains unchanged. ### Application-Owned Constraints Retain an optional application interface for registering collections and imposing their identity definitions. Configuration may define identity where no application constraint exists. When a declaration omits `key`, an applicable registration supplies identity. An explicit equivalent definition is accepted, and a different definition fails under every mode, including replace. For example, if the application requires `id`, `key: [id, name]` is invalid: that compound identity would allow repeated `id` values with different names. A registration is an authoritative constraint, not an omission-filling default. Copying a collection through inheritance does not create another application registration; registrations constrain their registered destinations. Identity constraints validate actual sequences. They do not independently require a path to exist, be non-null, or have sequence shape. The application schema and validation own those requirements. Final-result enforcement for application registrations is defined under [Validation And Diagnostics](#validation-and-diagnostics). ### Application Registration API Use one public sequence-identity registration type, collected in one field on `Definition`. Each registration contains an explicit destination selector and its identity fields. Exact and dynamic registrations share matching, overlap validation, identity comparison, and lifecycle behavior. Provide two constructors returning that same registration type: - An exact-path convenience constructor accepting a literal `Path` and identity field names. It converts the path into a selector containing literal segments. - An explicit-selector constructor accepting a structural selector and identity field names, for destinations that include arbitrary mapping keys. Both constructors accept identity fields as variadic strings, so one-field and compound identities use the same construction form. Apply the settled field-set rules, including deduplication. Invalid registrations, including an empty identity field set, fail during application-definition validation. Existing `Path` values retain their literal meaning throughout ConfigKit. The exact-path constructor supplies convenience at the registration boundary; dynamic matching uses the explicit selector type. Both forms can appear together in the same definition field. Replace the current registration shape with this model. Preserving the existing `SequenceComposition` fields and `Definition.SequenceCompositions` spelling is not a requirement, and no compatibility facade is needed solely to retain that syntax. Choose names centered on sequence identity, reflecting its role in composition, inheritance, and final validation. Exact Go type, field, and constructor names and signatures belong in the implementation plan. ### Dynamic Application Registration Destinations Allow applications to register identity for collections whose containing mapping keys become known only during loading. For example: ```yaml collections: weatherreporter: prompts: - id: foo.bar text: Report the weather. homewatch: prompts: - id: foo.bar text: Report the household status. ``` One application registration can require `id` for every namespace's `prompts` list. The equal IDs above are valid because each list has its own uniqueness scope. An optional root `prompts` list can have a separate exact registration. Use an explicit application-side structural selector composed of literal mapping keys and an arbitrary-mapping-key segment. Conceptually, the namespace rule is: ```text Literal("collections") -> AnyMappingKey -> Literal("prompts") ``` This notation explains the selector; it is not a Go signature or YAML syntax. Each segment consumes exactly one mapping level. Match the complete destination, not an arbitrary prefix or suffix. Literal keys remain exact, including empty strings and keys containing punctuation such as `*`, `/`, or `.`. An arbitrary-key segment is distinct from any literal spelling and does not match a sequence index. Existing `Path` values retain their literal meaning. This capability belongs to the reusable application definition and applies to ordinary and layered loads. YAML collection destinations and import destinations retain their existing literal syntax. Recursive search, regular expressions, filesystem glob rules, sequence-index selectors, and custom matching callbacks are outside this addition. At each concrete matched destination, apply the same authoritative identity constraint as an exact registration. Use the settled field-set and scalar-equality rules. Do not pool identities across destinations or require records to repeat the containing mapping key as an identity component. Applications retain ownership of namespace interpretation, qualified runtime IDs, and domain validation. Matching supplies effective identity before relevant strict composition and precedence operations. Without an applicable explicit mode, this identity selects upsert under the existing default rule. It also supplies identity for inheritance within the matched sequence. YAML declarations must agree with it under every mode, including replace. These are ordinary application constraints with a broader destination selector, not a separate final-validation facility. ### Registration Overlap Equivalent application constraints coalesce at any shared destination. Equivalence uses the identity field-set rules: for example, `id` and `[id, id]` agree. Incompatible constraints fail; exact registrations do not override broader selectors, and registration order grants no precedence. Detect incompatible overlapping registrations while validating the application definition, before source acquisition. For these fixed-depth mapping selectors, overlap exists when the selectors have the same number of segments and every corresponding pair can match a common key. Unequal literal keys at any position make the selectors disjoint; an arbitrary-key segment can overlap a literal or another arbitrary-key segment. Compare segment structure rather than rendered path strings. No configuration pre-read is needed. Thus an `id` rule for all namespace prompt lists conflicts with a `[id, name]` rule for one named namespace, even if that namespace is absent from a particular load. This is an invalid application definition. A valid selector matching no collections is harmless: registration does not require a path to exist, create collections, or impose shape and nullability requirements. ### Matching Across The Loading Lifecycle Match application selectors against effective configuration destinations after accounting for input placement. Physical filenames and source-local paths do not determine applicability. Make constraints available before composing contributions at those destinations, including namespaces first introduced by imports, mounted inputs, or higher tiers. Apply matching constraints to key-only YAML declarations as well, even before their sequence exists. Consumers need neither a preliminary load nor source inspection to enumerate namespaces. During inheritance, apply registrations at the inheriting destination, including newly created matching destinations. Copying a collection does not transfer its application registrations to a different path. The existing YAML-policy ownership and transfer rules remain separate from application selector matching. During final validation, find matching actual sequences in the final effective configuration. This includes namespaces introduced or replaced by typed defaults, CLI overrides, and application resolution. Reusing only destinations found during source assembly would miss these values. Use the same selector meaning and identity validator in both phases; later assignments do not trigger composition or inheritance again. YAML-only identities retain their existing enforcement boundary. ## Strict Composition And Precedence Operations ### Compose Peers Before Applying Precedence Resolve applicable identity and mode policy, strictly compose the tier's peer contributions, then apply one selected operation per collection against the accumulated lower value. The tier operation does not sequentially replace peer source contributions. Selected overlay contributions use the same combination semantics. Within a strict tier, equivalent identity definitions coalesce and different field sets fail. Agreeing explicit modes coalesce; conflicting explicit modes fail. Omission expresses no preference. A root declaration or a later declaration has no precedence over conflicting peers. Explicitly selecting a default mode is still a real instruction and can conflict with another explicit mode. Identified peer sequences append distinct records. Duplicate identities among peers or within a contributed list fail under all three modes, including replace and upsert. Equal or disjoint record payloads do not excuse a duplicate identity. Unidentified sequences retain their current strict-composition conflict behavior. For example, higher-tier fragments `[C]` and `[D]` with an agreed identity assemble as `[C, D]`. Against lower `[A, B]`, append or upsert produces `[A, B, C, D]`, while replace produces `[C, D]`. Peers `[B]` and `[B*]` conflict even under upsert because neither has higher precedence. ### Available Operations Use one spelling for each mode: `replace`, `append`, and `upsert`. | Mode | Behavior at source-precedence and inheritance boundaries | | --- | --- | | `replace` | Replace the complete lower sequence with the assembled higher sequence. | | `append` | Retain lower records and append higher records; duplicate identities fail. | | `upsert` | Replace matching records in full, retain unmatched lower records, and append new identities. | Append and upsert require effective identity. ConfigKit does not infer identity from an `id` field or record position. Whole-sequence replacement does not require identity agreement with lower YAML policy, but application constraints still apply. Letters denote record identities; `B*` has the same identity as `B` with a different payload: | Lower | Higher | Mode | Result | | --- | --- | --- | --- | | `[A, B]` | `[C]` | `append` | `[A, B, C]` | | `[A, B]` | `[C]` | `replace` | `[C]` | | `[A, B]` | `[B*]` | `append` | Duplicate-identity error | | `[A, B]` | `[B*]` | `replace` | `[B*]` | | `[A, B]` | `[B*]` | `upsert` | `[A, B*]` | | `[A, B]` | `[B*, C]` | `upsert` | `[A, B*, C]` | Upsert replaces the whole matched record. If lower `B` has `id`, `text`, and `temperature`, while higher `B` has only `id` and `text`, the result at this boundary has only `id` and `text`. Subsequent defaulting or other lifecycle operations retain their own semantics. Mappings continue to combine recursively; matching sequence records do not recursively merge fields. ### Mode Selection And Persistence Select the operation in this order: 1. Reconcile explicit modes within the current tier; conflicting peers fail. 2. Use the current tier's explicit mode if supplied. 3. Otherwise retain an applicable explicit mode from a lower tier. 4. With no explicit mode, infer upsert when effective identity is available. 5. Otherwise infer replace. Effective identity can come from an application registration, current declarations, or applicable lower policy, subject to the identity agreement and lifetime rules below. Determine the inferred mode from available identity before applying the operation. A plain higher-tier sequence can therefore use upsert without repeating a key declaration. An explicit mode persists at its applicable destination until a higher-priority explicit declaration changes it. New sequence values alone do not reset it, and an unrelated overlay leaves it intact. A mode-only declaration can change policy without supplying records; it neither clears the collection nor retroactively recombines earlier tiers. Later source contributions and inheritance use the resulting policy. | Lower explicit mode | Higher declaration | Effective mode | | --- | --- | --- | | `append` | Mode omitted | `append` | | `append` | `upsert` | `upsert` | | `upsert` | `replace` | `replace` | | None | Mode omitted, effective identity available | Inferred `upsert` | | None | Mode omitted, no effective identity | Inferred `replace` | Only explicit modes persist. Inferred defaults are recomputed from effective identity when needed. Explicit replace continues to apply in subsequent tiers until another mode is declared; introducing identity alone does not override it. Mode persistence does not preserve YAML identity discarded by replacement, nor policies owned by discarded records. Source precedence and inheritance use the same destination policy, without separate per-phase settings. CLI assignments remain outside mode selection. ### Presence, Empty Sequences, Null, And Kind Mismatches At a collection's precedence boundary: | Higher contribution | `replace` | `append` / `upsert` | | --- | --- | --- | | Absent | Leave the lower value unchanged. | Leave the lower value unchanged. | | Explicit `[]` | Clear the sequence. | Contribute no records. | | Explicit null or another non-sequence value | Ordinary replacement, subject to application schema. | Error: the operation requires a sequence. | A declaration alone does not clear a collection. An optional import selecting nothing contributes nothing and does not erase existing records. An absent lower collection can be initialized by an incoming sequence under any mode, subject to identity requirements. Explicit lower null or another non-sequence value is not absence: append and upsert fail against it, while replacement remains available. An empty incoming sequence bypasses neither kind checks nor identity requirements. With effective identity and no explicit mode, `prompts: []` uses upsert and does not clear the collection. Clearing requires replace, selected in the current tier or retained from lower policy. Replacing an identified collection with null also requires replace and a schema permitting null. Collection null is distinct from a present null identity component inside a record. ### Ordering Retain existing dependency-ready source scheduling within each tier and authored item order within lists. Gathering declarations does not change assembly order; identity values do not sort records. - Append keeps lower records in order, followed by higher records in assembled order. - Replace keeps only higher records in their assembled order. - Upsert keeps a matched record's lower position and appends new identities in higher-tier order. For example, lower `[A, B, C]` and higher `[C*, A*, D]` produce `[A*, B, C*, D]` under upsert. Whole-sequence replacement gives the higher tier control of the complete sequence order. ## Policy Agreement, Lifetime, And Ownership ### Identity Agreement And Replacement Append and upsert use one agreed identity for all participating records: | Lower identity | Higher declaration | Result when combining records | | --- | --- | --- | | `id` | Omitted | Use `id`. | | `id` | `id`, `[id]`, or `[id, id]` | Accept the equivalent definition. | | `id` | `[namespace, id]` | Error: different definitions. | | None | `id` | Establish `id` and validate all participating records. | Introducing identity for an unkeyed lower sequence requires checking both lower and incoming records, including uniqueness within each contribution. With no identity from the application or either participating collection, append and upsert fail. YAML identity follows the collection that survives an operation: | Operation | Effective YAML identity | | --- | --- | | Append or upsert | Retain or establish the agreed identity. | | Whole-sequence replacement | Discard lower YAML identity and use the replacing tier's identity declaration, if any. | | Replacement by null or another non-sequence value | Discard lower YAML identity and retain any identity explicitly declared by the replacing tier. | Application constraints remain authoritative under every operation. Without an application constraint, replacement can introduce a different identity, such as changing from `id` to `name`. Replacing a sequence without a new key declaration or application registration produces an unkeyed sequence. No identity-removal directive is needed. The reset occurs only when the collection value is actually replaced. Declaring replace without supplying a replacement does not authorize changing the identity of retained records. Explicit mode lifetime is separate from YAML identity lifetime. ### Ancestor Replacement Replacing an enclosing mapping can remove a collection without replacing that collection directly. Apply the same identity and ownership rules to this removal: discard the removed collection's lower YAML identity, and discard policies owned by any removed records. Reintroducing the same path later does not restore those discarded policies. Independently declared explicit modes retain their existing persistence rules. Removing a descendant collection does not remove a mode whose declaring scope survives. Application registrations remain applicable at matching destinations, including destinations reintroduced later. Identity newly declared by the replacing tier follows the existing declaration and ownership rules. For example, a root-level declaration establishes `key: id` and `mode: append` for `[catalog, prompts]`. A higher tier replaces `catalog` with null, removing the prompts collection and its YAML identity. The independently declared append mode survives. If a later tier recreates `catalog.prompts`, append requires identity supplied by a new declaration or an application registration. Without that identity, loading fails; the later tier can instead explicitly choose replace. The replacement of `catalog` itself follows ordinary ancestor-value precedence and does not attempt to append null to the removed prompts list. ### Declarations Without Sequence Values A key declaration without accompanying records applies immediately to an existing retained sequence: check agreement and validate its records, without recombining earlier tiers. For example, a higher tier that only declares `destination: [prompts], key: id` identifies and validates the retained lower `prompts` sequence. If no collection exists, retain the declaration in its owning scope for later contributions. An otherwise empty underlay can establish identity for main-tier fragments. An explicit identity declaration can also remain pending at a non-sequence destination; it does not independently impose a shape requirement. The presence and kind rules still determine whether an attempted operation fails. Item-local declarations retain their ownership boundaries. ### Lower-Tier Identity During Strict Composition Resolve applicable identity before composing a higher tier's peers, using application registrations, available lower-tier policy, and declarations gathered within the higher tier's scope. Authors need not repeat a baseline key solely because the higher tier has multiple fragments. For example, an underlay establishes `key: id` for `prompts`, and two main-tier fragments contribute `[foo]` and `[bar]` without a key declaration. They strictly compose as `[foo, bar]` before the main tier combines with the accumulated lower collection. If both contribute `foo`, composition fails; upsert does not give precedence to peers. Lower YAML identity remains subject to agreement, replacement, and ownership. A replacing collection must not be constrained by obsolete lower identity just because policy resolution precedes composition. Likewise, a replacement record cannot borrow nested identity owned by the discarded lower record, even when outer identity or numeric position matches. Application constraints still apply. Higher-tier declarations do not retroactively repair invalid lower-tier composition. ### Nested Record Ownership Attach item-local policies to their owning contributions so they follow surviving records independently of numeric indexes. Whole-record upsert discards the old record's local policies along with its fields. Whole-sequence replacement discards policies owned by removed records. A replacement record supplies its own local declarations; equal outer identity or final index does not transfer discarded policies. For example, a source imported as one record into `prompts` can declare: ```yaml configkit: sequences: - destination: [steps] key: id mode: append id: foo steps: - id: prepare ``` The declaration governs `steps` inside that `foo` record. Retaining `foo` retains its local policy, including the explicit mode. Upserting a new `foo` discards the old `steps` and its declaration even though the outer record keeps its position. Policies independently applicable at a destination are not discarded merely because an individual record is replaced. Ownership determines which declarations are removed. Application registrations remain constraints at their registered destinations. Inheritance copies transfer identity and choose operations as specified next. ## Sibling Inheritance Complete source-tier assembly before resolving inheritance. Retain existing mapping-sibling scopes and add identified-sequence scopes as described below. Both use the existing dependency-ready algorithm. At each inheritance combination, the resolved parent's collection is the lower value and the inheriting mapping's local collection is the higher value. Mappings combine recursively; upsert within an identified sequence remains whole-record replacement. Explicit record inheritance is a separate construction step after those replacements. Use the inheriting destination collection's policy: an applicable explicit mode, including one retained through source tiers, wins. Otherwise infer upsert with effective identity and replace without it. There is no separate default-append rule for inheritance. The same destination policy governs source-precedence and inheritance combinations. YAML identity follows a collection copied through inheritance, subject to agreement and replacement rules. A source collection's mode does not automatically become an instruction at a different inheriting destination. For example, source `steps` has `key: id` and `mode: append`; an inheriting mapping supplies local `steps` without an applicable explicit mode. The copied identity selects upsert there. An explicit destination append instead selects append. A matching destination key agrees; a different key conflicts when combining records, while explicit replace can establish new YAML identity subject to application constraints. For example: ```yaml configkit: sequences: - destination: [parent, items] key: id child: items: - id: foo value: A - id: bar value: B parent: extends: child items: - id: baz value: C ``` Despite the names, `parent` inherits from `child`. Identity at `[parent, items]` selects upsert, producing `[foo, bar, baz]`. If the local sequence instead supplies a revised `foo`, the result is `[foo*, bar]`. Append rejects that repeated identity; replace retains only the local sequence. The same ordering, presence, and kind rules apply at inheritance boundaries. An omitted local sequence retains the inherited sequence. Explicit `[]` clears it under replace and contributes no records under append or upsert. Retain controls until inheritance uses them, then exclude them from application decoding. ### Inheritance Between Identified Sequence Records An identified sequence supplies a sibling scope for its records. Identity can come from an application registration or an applicable YAML declaration. A record may inherit from one other record in that same sequence using an `extends` mapping that selects the parent's complete identity: ```yaml configkit: sequences: - destination: [prompts] key: id prompts: - id: base model: standard temperature: 0.5 - id: concise extends: {id: base} temperature: 0.2 ``` The final `concise` record is: ```yaml id: concise model: standard temperature: 0.2 ``` The `base` record remains in the collection. Parents are ordinary records subject to the same decoding and validation as other records; there is no abstract template category. Use mapping-form references for both single and compound keys. With `key: [namespace, id]`, a reference can be `extends: {namespace: shared, id: base}`. Match components using the collection's field-set and scalar-equality rules, including mathematical numeric equality. `extends: {id: null}` selects a null-valued identity; `extends: null` cancels a relationship. Parent-reference mappings use ordinary strict mapping composition. Item-local helper imports may supply disjoint fields of a compound reference; overlapping fields conflict, even when equal. For example, a helper's `extends: {namespace: shared}` and the importing record's `extends: {id: base}` compose into `extends: {namespace: shared, id: base}`. This assembles one record; it does not permit strict peers to contribute duplicate record identities. Before parent lookup, require the surviving effective reference mapping to contain exactly the collection's identity fields, with supported scalar values. Missing or extra fields fail. Validate the completed reference during inheritance, rather than requiring each helper contribution to be independently complete. Superseded references remain historical evidence; earlier strict-composition conflicts remain errors. Every record must supply its complete own identity before inheritance. Preserve the child's identity fields and inherit only the parent's nonidentity payload; inheritance cannot supply a missing child identity. Child payload fields take precedence, mappings combine recursively, and nested sequences use the inheriting destination's collection policy. Consume the record's directive before decoding. Support one parent within the same identified sequence, including forward references and chains. Missing parents and cycles, including self-reference, fail the load. Cross-collection references, position-based references, multiple parents, and inheritance between unidentified sequence members are outside this scope. Existing string-form references between mapping siblings retain their meaning; they do not become shorthand for sequence identity references. Resolve relationships against records surviving source-tier assembly and selected overlays. A higher layer can replace a parent before inheritance runs; removing that parent makes a surviving reference fail. Whole-record upsert discards the old record's directive along with its payload. Omitting `extends` in the replacement record does not retain the displaced record's relationship. An explicit reference to the record's own identity is a cycle, not a way to access its lower-tier predecessor. Reuse Kahn's algorithm with the existing stable canonical semantic-pointer key for dependency-ready ordering. Build parent lookup from the sequence's effective identity, and preserve the assembled list order independently of resolution order. Enclosing relationships resolve before nested relationships. Parent templates retain nested instructions for evaluation at each inheriting destination, following the existing destination-local inheritance rule. Copied collection identity, destination operation selection, and record-owned policy transfer follow the rules above. Record inheritance runs in the existing structural phase, before typed defaults, decoding, CLI overrides, and application resolution. Those later stages do not trigger another inheritance pass. Preserve inherited presence, origin and history evidence, sensitivity, declaring resource contexts, and existing expansion budgets just as for mapping-sibling inheritance. Identity lookup must not expose identity values in diagnostics. Existing index-based inspection paths remain sufficient; no new identity-selector path API is needed. ## Loading Lifecycle Use the following order: 1. Assemble source tiers and selected overlays, resolving policy before each tier's strict composition and applying collection operations at precedence boundaries. 2. Resolve sibling inheritance in mappings and identified sequences, then apply typed defaults and decode the assembled configuration. 3. Apply explicit CLI overrides to that configuration and check supplied values against the application schema. 4. Run application resolution against the overridden configuration. 5. Resolve effective secret references, validate the final configuration including application-registered identities, and publish it. ### Typed Defaults And Application Resolution Source-backed underlays, including application-supplied mapping sources, participate in sequence combination. Typed `Definition.Defaults` remains the initial decoded state: supplied sequences replace default sequences. Source append does not append to a typed default list. Application resolution retains assignment and recorded-transformation semantics. ConfigKit does not automatically combine a callback's assigned sequence with its previous value. Application-registered identities receive final validation independently of how defaults, CLI overrides, or callbacks produce their values. ### CLI Precedence CLI overrides are the highest-precedence input to application resolution. Supplied sequences replace whole sequences, including sequences inside supplied mappings. Mappings retain recursive override behavior; empty sequences and permitted nulls retain explicit replacement meaning. Configuration append or upsert does not reinterpret CLI assignments. Inheritance and defaulting do not run again afterward: overriding assembled `[A, B]` with `[C]` presents `[C]` to application resolution without inheritance reintroducing prior records. Application resolution sees CLI values and their explicit-presence and source metadata. `Resolution.Default` preserves explicit CLI values; normalization and recorded application transformations may still change them. For example, a derived URL can use a CLI hostname, while an explicit CLI URL can be preserved by an absence-based default. Retain recording and provenance requirements for those transformations. Reject structural directives such as `extends` and `configkit` in CLI override paths or supplied values. CLI input supplies application values after structural processing; it cannot supply or cancel inheritance directives, change completed relationships, or prevent earlier inheritance failures. Typed decoding also precedes CLI application, so a CLI replacement cannot repair an earlier decoding failure. A source string in an integer field fails before a valid CLI integer can apply. This changes current override-before-decoding behavior. Semantic validation remains after overrides and application resolution. Secret lookup uses effective references after overrides and resolution. Neither stage bypasses final application identity constraints or semantic validation. ## Validation And Diagnostics ### Structural Identity Checks Allow item-local helper imports to complete and consume applicable non-main source-version headers before checking payload identity for collection assembly. A helper can supply an identity component; a consumed header cannot supply one after removal. Structural controls are likewise unavailable as source identity components. Check identity against application payload fields, excluding fields acting as structural directives even when the engine retains them for later processing. For example, `key: extends` with an item containing `extends: null` does not supply a null identity: that field cancels inheritance and is consumed. Report the ordinary missing-identity-component error at the collection/item path using available origins, without exposing values. Do not defer this failure until directive consumption or final application validation. This rule follows a field's structural role; it does not introduce a broader restriction on unrelated literal field names. Final application identity checks continue to examine the effective typed payload under their existing rules. Validate each identified contribution before combination and check uniqueness in the resulting identified collection, including inheritance operations. Upsert matches across precedence are replacements; duplicates within a contribution remain errors. Later inheritance, typed defaults, or callbacks cannot repair an identity missing at an earlier assembly boundary. YAML-only identities are enforced during structural composition, precedence assembly, and identified inheritance operations. They have no final-result guarantee after typed defaulting, CLI overrides, or application resolution. Those stages can produce duplicate identities or otherwise violate a YAML-only identity. Applications needing a final guarantee register the constraint through the application-owned interface. Adding record inheritance does not expand this guarantee: a YAML declaration can enable parent lookup without imposing final validation on values later produced by defaults, CLI overrides, or application resolution. ### Final Application Constraints On successful loading, final effective collections covered by application registrations satisfy their declared identity constraints. Retain assembly-time checks and validate final effective sequences before publication, after defaults, inheritance, overrides, application resolution, and secret lookup. This covers both exact and dynamic application registrations. Evaluate dynamic selectors against the final effective configuration, with independent validation for each concrete matched sequence as described under [Matching Across The Loading Lifecycle](#matching-across-the-loading-lifecycle). ConfigKit performs these identity checks; consumers register the constraint without needing to repeat duplicate detection in `Definition.Validate`. Application-owned semantic validation continues to cover domain-specific rules. This guarantee covers actual sequences, not path existence or allowed shape. It does not require every intermediate callback state to satisfy the constraint and does not cover caller mutations after loading returns. Final checks examine effective typed values; assembly checks validate authored contributions. A final scalar alone does not prove that a source explicitly supplied that field. Use the existing canonical final-value representation and shared publication path as the foundation. The guarantee requires neither a new mutation-history system nor exact causal reconstruction for records supplied by defaults or callbacks. ### Diagnostics And Inspection Identity diagnostics identify collection and item paths using available origin information without exposing identity values. Conflicting declarations identify the collection destination and declaration locations. For dynamic registrations, use concrete matched collection and item paths for value diagnostics, with available origins and existing sensitivity rules. Definition-time overlap errors identify the conflicting registrations; they do not require or invent a concrete destination from a loaded document. Correctness includes final values, projected item paths, source destinations, provenance, history, sensitivity, and passive resource contexts. Appending can change final indexes; replacing changes which contributions survive. Preserve the existing loading and inspection contracts through both operations, including policy ownership and inheritance transfer. ## Work Needed From The Baseline The baseline needs the following connected capabilities to reach the target state. Execution order and test sequencing belong to the [implementation plan](implementation.md): - **Declarations and public API:** extend application registration to the settled identity model with one public registration type and definition field, an exact-path convenience constructor, and an explicit-selector constructor. Preserve literal `Path` semantics. Parse and consume `configkit.sequences` across supported source forms and selected overlays; preserve placement-relative and item-local scopes. Keep sequence declarations independent of filesystem import enablement. - **Identity and policy representation:** implement field-set comparison, typed scalar identity tuples with exact numeric equality, declaration agreement, pending declarations, explicit-mode persistence, replacement lifetime, and record-owned policy transfer. Choose bookkeeping proportional to these semantics. Handle descendant collection removal through ancestor replacement, preserving independently declared modes and application constraints while discarding removed collection identity and record-owned policies. - **Registration matching:** support literal and arbitrary-mapping-key segments, detect incompatible selector overlap during definition validation, and resolve applicable constraints at concrete placed destinations. Reuse the identity rules and validator for exact and dynamic registrations. Keep matching separate from source discovery and from YAML declaration ownership. - **Assembly handoffs:** make accumulated lower policy available before higher-tier strict composition. Separate source acquisition from policy-aware composition or otherwise revise assembly sequencing; current main-before-underlay composition is not a design constraint. Preserve distinctions among acquisition order, dependency-ready scheduling within tiers, and precedence order. Account for source records, callbacks, main-version checks, and failure diagnostics. Retain version ownership and validation semantics; higher replacement cannot hide lower-tier structural failures. - **Combination and inheritance:** implement the three operations with strict peer handling, whole-record replacement, presence rules, stable ordering, and the destination policy rules for inheritance. Extend sibling-scope discovery and parent lookup to identified sequences, validate mapping-form references, and preserve child identities while copying parent payloads. Reuse the shared dependency-ready scheduler and destination-local nested resolution. Preserve provenance, history, sensitivity, paths, and resource contexts as records survive, move, or disappear. - **Lifecycle and validation:** move CLI application after inheritance and typed defaults/decoding, preserve explicit-presence and source metadata for application resolution, reject CLI structural directives, and add final application identity validation through the shared publication path. Keep YAML-only enforcement within structural operations. Match dynamic registrations during assembly and inheritance, and against the final effective configuration rather than a saved list of source-backed destinations. Exclude structural controls from source identity checks even while retaining those controls for later inheritance processing. - **Documentation and verification:** exercise ordinary and layered loading, imported and inline collections, item-local scopes, version-header consumption, selected overlays, inheritance, typed defaults, CLI, callbacks, and inspection. Cover single and compound parent references, scalar equality, forward references and chains, missing parents and cycles, parent replacement/removal, child identity preservation, nested destination policy, cancellation, and stable output order. Verify helper-composed references, overlapping reference fields, missing or extra fields, and replacement of references together with their containing records. Verify independent namespace uniqueness, root and namespaced registrations, literal punctuation keys, equivalent and incompatible overlaps, and conflicts detected even without a matching input destination. Cover namespaces introduced by imports, placement, higher tiers, inheritance, defaults, CLI, and callbacks; preserve ordinary strict-peer and upsert behavior. Check YAML disagreement under replace, harmless absent or empty collections, schema-owned shape requirements, unrelated sequences remaining unselected, and concrete-path diagnostics. Verify both constructors feed the same registration model, including mixed exact and dynamic registrations, compound identities, and definition-time rejection of empty identity field sets. Cover ancestor replacement followed by collection reintroduction, including a surviving append mode with and without renewed identity, explicit replacement, and application-registered identity. Verify that `extends: null` cannot supply an identity component and that structural-control exclusion uses ordinary value-free missing-identity diagnostics. Update the public contract and consumer examples when behavior lands. The collection-policy and CLI-ordering decisions are accepted in [ADR 0017](../adr/0017-collection-sequence-policy.md) for collection policy and [ADR 0018](../adr/0018-cli-after-structural-resolution.md) for CLI ordering. Their scoped supersession is recorded in the affected earlier ADRs, and the [architecture policy](../policy/architecture.md) reflects the accepted decisions. These govern the target architecture; the configuration contract continues to describe implemented behavior until the feature lands. This roadmap does not select migration machinery. ADR 0017 now includes inheritance within identified sequences; [ADR 0009](../adr/0009-sibling-inheritance.md) records that scope extension in its status while preserving its decision content. The architecture policy is aligned. Dynamic selectors extend the destinations covered by application registration; they retain the accepted application authority and final-validation boundary. No open feature decisions remain. The implementation plan translates this end state into reviewable stages without adding guarantees, restrictions, or combination semantics.