diff --git a/docs/roadmap/sequences.md b/docs/roadmap/sequences.md index cdbf789..b6341e7 100644 --- a/docs/roadmap/sequences.md +++ b/docs/roadmap/sequences.md @@ -1,10 +1,9 @@ # Sequence Identity And Combination -Status: feature roadmap with OD-1 through OD-10 settled and follow-up interaction -decision OD-11 open. The original decisions establish the intended operations; -the remaining question addresses nested policy ownership and transfer. -Resolve it before preparing a staged implementation plan. This is -not an implementation plan or an implemented contract. +Status: feature roadmap with OD-1 through OD-11 settled. A whole-roadmap review +identified the remaining policy-lifetime clarification in OD-12 below. Resolve it +and review the completed roadmap before preparing a staged implementation plan. +This is not an implementation plan or an implemented contract. ## Motivation @@ -116,7 +115,7 @@ 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 those source and item-local scope boundaries. -OD-11 addresses policy ownership when enclosing records are replaced or inherited. +OD-11 settles policy ownership when enclosing records are replaced or inherited. Identity and mode can be supplied independently. Omitted identity can use an application registration; an explicit matching declaration is accepted, and a @@ -685,7 +684,12 @@ paths or supplied values. CLI overrides supply application values after structur processing; they do not initiate a second inheritance pass. This deliberately changes the current ability to supply or cancel `extends` through CLI input. CLI changes cannot prevent an earlier inheritance failure or change which -relationships that completed pass resolved. +relationships that completed pass resolved. Likewise, because typed decoding +precedes CLI application, an invalid source value that fails decoding cannot be +repaired by a CLI replacement. For example, a string supplied for an integer +field fails before a valid integer override can apply. This differs from the +current override-before-decoding behavior. Semantic validation remains after +overrides and application resolution, as specified above. This ordering supersedes the current CLI-before-inheritance lifecycle described in [ADR 0009](../adr/0009-sibling-inheritance.md). It avoids special replacement @@ -727,7 +731,8 @@ 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 +ownership and transfer, including the distinction between surviving records and +inheritance copies. CLI overrides remain outside sequence mode selection under OD-8. Strict peer composition and all ordering rules in OD-4 are unchanged. ### Lower-Tier Identity During Strict Composition @@ -753,8 +758,11 @@ Determine applicability using OD-3's agreement and replacement rules: append and upsert require agreement, while whole-sequence replacement may change or discard YAML-only identity. A replacing collection must not be constrained by an obsolete lower identity merely because policy resolution precedes strict composition. -Application registrations remain authoritative. Higher-tier declarations do not -retroactively repair invalid lower-tier composition. +Application registrations remain authoritative. Under OD-11, a replacement +record also cannot borrow item-local identity owned by the discarded lower +record, even if both records have the same outer identity or numeric position. +Higher-tier declarations do not retroactively repair invalid lower-tier +composition. Separate source acquisition from policy-aware composition, or otherwise revise assembly sequencing, so accumulated lower policy is available before higher-tier @@ -766,6 +774,59 @@ main-version checks, and failure diagnostics when changing the handoffs. Retain version ownership and validation semantics; do not use higher-tier replacement to hide lower-tier structural failures. +### Nested Policy Ownership And Transfer + +**OD-11: settled.** + +Attach item-local collection policies to their owning contributions. Policies +follow surviving records independently of numeric indexes. Whole-record upsert +replacement discards the old record's local policies along with its fields; +whole-sequence replacement likewise discards policies owned by removed records. +A replacement record supplies its own local declarations. Sharing an outer +identity or occupying the same final index does not transfer the discarded +record's policies to its replacement. + +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 particular `foo` record. Retaining +`foo` retains its local policy, including its explicit mode under OD-9. Upserting +a new `foo` discards the old `steps` and its declaration; the replacement does not +inherit either merely because upsert retains the outer record's position. + +Distinguish inherited collection identity from operation instructions. YAML +identity follows a collection copied through sibling inheritance, subject to +OD-3's agreement and replacement rules. The inheriting destination selects its +operation under OD-7 and OD-9; the source collection's mode does not automatically +become an instruction at the new destination. + +For example, a source mapping's `steps` collection has `key: id` and +`mode: append`. An inheriting mapping supplies local `steps` but no applicable +explicit mode. The copied identity selects upsert at the inheriting destination; +the source's append mode remains applicable at its own destination. An explicit +append declaration at the inheriting destination instead selects append there. +A destination declaration of the same key agrees; a different key conflicts when +combining records, while explicit replacement can establish a new YAML identity +under OD-3. + +Application registrations remain constraints at their registered destinations; +copying a collection does not create another application registration. Policies +that independently apply at the destination are not discarded merely because +an individual record is replaced. Ownership determines which declarations are +removed. This preserves OD-9's persistence rule for applicable explicit modes +without retaining declarations owned by discarded records. The implementation +plan should choose the bookkeeping needed to preserve these distinctions. + ## Architectural Direction The settled collection declaration gives imported and inline records at the same @@ -812,30 +873,42 @@ Public API design and test sequencing belong to that later plan. ## Open Decisions -### OD-11. Nested Policy Ownership And Transfer +### OD-12. Identity Declarations Without Sequence Values -OD-2 allows collection declarations inside imported items, and OD-3 ties YAML-only -identity to surviving collections. Specify what happens to those policies when -an enclosing record is upserted, replaced, moved, or copied through inheritance. -For example, replacing record `foo` wholesale must account for the old record's -declaration governing `foo.steps`; keeping the numeric index alone does not -establish that the old policy still belongs there. +OD-9 defines a mode-only declaration without accompanying records. Clarify the +corresponding behavior for `key`, including a declaration made before any sequence +exists, and complete OD-3's identity-lifetime rule for non-sequence replacement. +These cases must have defined results before the implementation plan chooses how +to store collection policy. -**Recommendation:** Attach item-local policies to their owning contributions so -they follow surviving records independently of numeric indexes. Whole-record -replacement discards policies owned by the discarded record. Distinguish inherited -collection identity from operation instructions: copied identity may follow a -surviving collection, while the inheriting destination selects its operation under -OD-7. Application registrations remain constraints at their registered destinations. -Provide nested examples showing retained records, replaced records, inherited -copies, and agreement with declarations at the destination. This protects the -established whole-record replacement semantics and prevents stale policies from -attaching to unrelated records after reindexing. +For example, a lower tier supplies an unkeyed `prompts` sequence and a higher tier +only declares `destination: [prompts], key: id`. Does this validate and identify +the retained sequence immediately? Can a declaration in an otherwise empty +underlay establish identity for main-tier fragments under OD-10? Conversely, if +an identified sequence is replaced by null, does its old YAML identity disappear? +OD-6 specifies the resulting values but does not fully specify these policy effects. -**Alternative:** Keep configuration policies solely in a destination registry and -rebind them after structural changes. This offers centralized lookup, but numeric -paths cannot safely identify changing records, and item-local declarations still -need ownership information to distinguish policies that should survive from -policies whose declaring records were discarded. Requiring declarations again at -each inherited destination reduces transfer rules but makes reusable fragments -more repetitive and would narrow the current identity-follows-collection model. +**Recommendation:** Allow identity declarations without accompanying records. +Apply the declaration to a retained sequence immediately, checking identity +agreement and validating its records; do not recombine earlier tiers. If the +collection is absent, retain the declaration in its owning scope for later +contributions without requiring the collection to exist. Merely declaring replace +without supplying a replacement value does not authorize changing a retained +collection's identity. Extend OD-3's replacement rule to any actual replacement +of the collection by a non-sequence value: discard the lower YAML-only identity, +retain any identity explicitly declared by the replacing tier, and preserve +application constraints. An explicit declaration can remain pending at an absent +or non-sequence destination without independently imposing a shape requirement; +OD-6 still governs whether an attempted operation on a non-sequence value fails. +These rules allow baseline policy declarations while keeping identity removal +tied to actual replacement. Explicit mode persistence remains governed by OD-9. + +**Alternative:** Require a YAML identity declaration to have a sequence in the +same tier. This keeps YAML identity attached only to concrete sequence values +and reduces pending-policy cases, but prevents policy-only baseline files and +requires authors to repeat declarations beside later contributions. It also +makes identity declarations less flexible than the settled mode declarations. +For non-sequence replacement, retaining the lower YAML identity until another +sequence appears is another viable choice; it supports persistent schema-like +policy, but conflicts with the current distinction between collection-owned +YAML identity and application-owned constraints and would require revisiting OD-3.