diff --git a/docs/roadmap/sequences.md b/docs/roadmap/sequences.md index 639eb42..9d185f5 100644 --- a/docs/roadmap/sequences.md +++ b/docs/roadmap/sequences.md @@ -1,7 +1,7 @@ # Sequence Identity And Combination -Status: feature roadmap with OD-1 through OD-8 settled and follow-up interaction -decisions OD-9 through OD-11 open. The original decisions establish the intended +Status: feature roadmap with OD-1 through OD-9 settled and follow-up interaction +decisions OD-10 and OD-11 open. The original decisions establish the intended operations; the new questions address their lifecycle and policy-scope boundaries. Resolve these questions before preparing a staged implementation plan. This is not an implementation plan or an implemented contract. @@ -125,12 +125,12 @@ require identity matching, but application-owned constraints still apply. Identity-policy lifetime across tiers is settled in OD-3 below. Mode describes the collection's combination instruction at source-precedence -and inheritance boundaries, as detailed in OD-7. A lower tier's -`append` does not silently select append for a later overlay. Gather collection -declarations before composing their relevant scope so their effect does not -depend on which contribution is assembled first. Identity agreement is settled +and inheritance boundaries, as detailed in OD-7. An explicit mode persists at +the same applicable destination until a higher-tier declaration changes it. +Gather collection declarations before composing their relevant scope so their +effect does not depend on which contribution is assembled first. Identity agreement is settled in OD-3; operation agreement and omission among peers are settled in OD-4. -OD-9 addresses which controls survive source precedence for later inheritance. +OD-9 settles how operation controls survive source precedence for later inheritance. Permit sequence declarations in selected overlays and make their use independent of filesystem import enablement. This deliberately changes the current blanket @@ -152,8 +152,9 @@ prompts: text: Revised definition ``` -The explicit `mode: upsert` line can be omitted here because `key: id` supplies -an effective identity. An overlay can instead select duplicate-rejecting append: +The explicit `mode: upsert` line can be omitted here when no different explicit +mode applies from a lower tier: `key: id` then supplies the identity for inferred +upsert. An overlay can instead select duplicate-rejecting append: ```yaml configkit: @@ -182,11 +183,12 @@ prompts: text: Baz definition ``` -Explicitly selecting the default operation is valid. Removing the last example's -`configkit` block produces the same replacement behavior only when no effective -identity is available. For an identified collection, explicit `mode: replace` -overrides the inferred `upsert`; it is not redundant. OD-5 defines the selection -rule for `replace`, `append`, and `upsert`. +Explicitly selecting the default operation is valid. With no applicable explicit +mode, removing the last example's `configkit` block selects replace only when no +effective identity is available; an identified collection instead selects upsert. +A retained explicit mode also affects omission. Explicit `mode: replace` overrides +either another retained mode or inferred upsert. OD-5 defines the selection rule +for `replace`, `append`, and `upsert`. Start with this common collection declaration and defer `key` and `mode` shorthand on imports. A single declaration form covers inline overlays and mixed @@ -306,7 +308,8 @@ The tier operation does not sequentially replace peer source contributions. Coalesce agreeing explicit modes for the same collection within a tier and reject conflicting explicit modes. Omission expresses no preference; apply the -default only after reconciling declarations. +effective-identity default only after reconciling declarations and checking for +an applicable explicit mode retained from a lower tier. | Modes declared within one tier | Effective operation | | --- | --- | @@ -314,12 +317,13 @@ default only after reconciling declarations. | `append` and omitted | `append` | | `replace` and omitted | `replace` | | `append` and `replace` | Error | -| All omitted | `upsert` with effective identity; otherwise `replace` | +| All omitted | Retain an applicable lower explicit mode; otherwise infer from effective identity | Explicitly selecting the default is a real instruction and can conflict with -another explicit selection. Different modes in different tiers are valid; a -lower tier's mode does not carry forward. Neither a root declaration nor a later -declaration wins over conflicting peers. Diagnostics identify the collection +another explicit selection. Different modes in different tiers are valid; the +higher tier's explicit mode replaces the lower mode, while omission retains it. +Neither a root declaration nor a later declaration wins over conflicting peers. +Diagnostics identify the collection destination and conflicting declaration locations. OD-5 defines mode names and the default-selection rule. @@ -376,21 +380,25 @@ Select the operation at each collection's precedence boundary in this order: 1. Reconcile explicit modes within the current tier under OD-4; conflicting explicit modes fail. -2. If an explicit mode is supplied, use it. -3. Otherwise, select `upsert` when an effective identity is available. -4. Otherwise, select `replace`. +2. If the current tier supplies an explicit mode, use it in place of a lower mode. +3. Otherwise, retain an applicable explicit mode from a lower tier. +4. If no explicit mode applies, select `upsert` when effective identity is available. +5. Otherwise, select `replace`. Effective identity may come from an application registration, a current-tier declaration, or the lower collection, subject to OD-3's agreement rules. Selection depends on identity availability, not on whether the current tier -explicitly repeats a `key` declaration. A plain overlay sequence can therefore -default to `upsert` when identity was established elsewhere. A lower tier's mode -does not carry forward. +explicitly repeats a `key` declaration. With no applicable explicit mode, a plain +overlay sequence can therefore default to `upsert` when identity was established +elsewhere. New sequence values do not reset an existing explicit mode. Inferred +defaults do not become persistent explicit instructions: when no explicit mode +applies, determine the default from the identity available at that boundary. Determine the inferred mode using the available identity before applying the -operation. Explicit `replace` still follows OD-3: discard the lower collection's -YAML-only identity with the lower sequence, use the replacing tier's identity -declaration if supplied, and preserve application-owned constraints. Selecting +operation. `replace`, including a retained explicit mode, follows OD-3: discard +the lower collection's YAML-only identity with the lower sequence, use the +replacing tier's identity declaration if supplied, and preserve application-owned +constraints. Selecting `append` or `upsert` explicitly still requires an effective identity. This default governs combination between tiers and during sibling inheritance @@ -525,10 +533,11 @@ non-sequence lower value is distinct from absence: append and upsert against it fail, while replacement remains available. An empty incoming sequence does not bypass these kind checks or the operation's identity requirements. -With effective identity available, an omitted mode selects upsert. Consequently, -`prompts: []` alone does not clear an identified collection. Clearing it requires -explicit `mode: replace`. Replacing an identified collection with null likewise -requires explicit replacement and an application schema that permits null. +With effective identity available and no applicable explicit mode, omission +selects upsert. Consequently, `prompts: []` alone does not clear such a collection. +Clearing it requires replace, selected explicitly in the current tier or retained +from a lower declaration. Replacing an identified collection with null likewise +requires replacement and an application schema that permits null. An application identity registration does not itself require the collection path to exist or be non-null, and does not independently reject non-sequence values. @@ -551,8 +560,9 @@ Complete source-tier assembly before resolving inheritance, retaining the existing dependency-ready inheritance algorithm and scope rules. At each inheritance combination, the resolved parent's collection is the lower value and the inheriting mapping's local collection is the higher value. Use the same -operation selection as source precedence: an explicit mode wins; otherwise use -`upsert` with effective identity and `replace` without it. There is no separate +operation selection as source precedence: the effective explicit mode wins, +including one retained under OD-9; otherwise use `upsert` with effective identity +and `replace` without it. There is no separate default-append rule for inheritance. Use the inheriting destination collection's controls. Its selected mode governs @@ -681,6 +691,44 @@ in [ADR 0009](../adr/0009-sibling-inheritance.md). It avoids special replacement markers carried through inheritance. Current contracts remain the implemented baseline until the architectural and implementation work lands. +### Persistent Operation Policy + +**OD-9: settled; this revises the earlier tier-local mode rule in OD-4 and OD-5.** + +An explicit mode is collection policy that persists at its applicable destination +until a higher-priority declaration changes it. Reconcile peers strictly within +each tier, then let a higher explicit mode replace a lower one. Omission retains +an applicable explicit mode regardless of whether the higher tier supplies new +sequence values. Source precedence and subsequent inheritance use the same +effective operation 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` | + +An unrelated overlay leaves the policy intact. A mode-only declaration may change +the policy without supplying records; it neither clears the collection nor +retroactively recombines earlier tiers. A later source contribution or inheritance +operation uses the resulting policy. Supplying values alone does not reset it. + +Only explicit modes persist. Inferred defaults are recomputed from effective +identity when needed. Thus explicitly selecting replace for an identified +collection continues to select replace in subsequent tiers until another mode is +declared; an author wanting upsert afterward must select it explicitly. Identity +availability and constraints still follow OD-3, including YAML-only identity +removal on whole-sequence replacement. Persisting a mode does not preserve an +identity that OD-3 discards. + +This persistence is scoped to the applicable collection. It does not transfer a +parent mapping's mode automatically to another destination through `extends` or +resurrect policies owned by discarded records. OD-11 addresses nested policy +ownership and transfer. CLI overrides remain outside sequence mode selection +under OD-8. Strict peer composition and all ordering rules in OD-4 are unchanged. + ## Architectural Direction The settled collection declaration gives imported and inline records at the same @@ -725,35 +773,6 @@ Public API design and test sequencing belong to that later plan. ## Open Decisions -### OD-9. Which Controls Survive Until Inheritance? - -OD-4 prevents a lower tier's mode from selecting a later tier's operation, while -OD-7 retains destination controls for inheritance after source assembly. The -roadmap needs an explicit rule for a collection left untouched by a higher tier, -a newly supplied sequence with no mode, and declarations supplied without values. -For example, does an unrelated selected overlay erase a main source's explicit -replace instruction for a collection that later inherits records? - -**Recommendation:** Distinguish untouched collections from new contributions. -Retain relevant controls for an untouched collection's later inheritance. When -a higher tier supplies a new sequence contribution, select its operation from -that tier's declarations and the effective-identity default; do not reuse the -lower mode. Permit a declaration without a sequence value to control later -inheritance without clearing the collection. Express these cases in a policy -lifetime table covering absent values, key-only and mode-only declarations, -explicit operations, and replacement of a collection or an enclosing subtree. -Identity changes must still satisfy OD-3. - -This preserves intentional inheritance controls across unrelated overlays while -keeping each new sequence contribution's precedence operation local to its tier. - -**Alternative:** Maintain a destination policy independently of value survival, -letting higher explicit policy fields override lower ones and omissions inherit -them. This makes declaration-only configuration straightforward, but modes can -become sticky when new values arrive. Applying that policy only to inheritance -would preserve OD-4 at the cost of two distinct policy-resolution rules; applying -it to source precedence would require revisiting OD-4. - ### OD-10. Identity Availability During Strict Tier Composition Suppose an underlay declares `key: id`, while two main-tier fragments contribute