From 6a4e57e5d36dd6a0c9439b68754511c1e874e2c4 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Thu, 22 Oct 2026 14:47:00 +0000 Subject: [PATCH] Settle sequence validation and absent value behavior --- docs/roadmap/sequences.md | 106 +++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 48 deletions(-) diff --git a/docs/roadmap/sequences.md b/docs/roadmap/sequences.md index e6c0a49..acd7161 100644 --- a/docs/roadmap/sequences.md +++ b/docs/roadmap/sequences.md @@ -267,9 +267,9 @@ removal directive is needed. Application registrations continue to constrain the replacement collection. If the application requires `id`, declaring `name` is invalid under every mode. The policy reset above applies when a sequence is actually replaced; effects of -absent contributions, null collections, and kind mismatches remain under OD-6. -These structural rules do not settle final-result enforcement for YAML-only -identity declarations, which remains the OD-1 follow-up. +absent contributions, null collections, and kind mismatches are settled in OD-6. +YAML-only identity declarations receive assembly-time enforcement, as settled +in OD-1 below. ### Combination Scope, Declarations, And Ordering @@ -342,8 +342,8 @@ For example, lower `[A, B, C]` and higher `[C*, A*, D]` produce preserves its position; whole-sequence replacement gives the higher tier control of the complete sequence order. -OD-5 settles default selection and operation naming. Absent contributions, empty -sequences, null, and kind mismatches remain under OD-6. +OD-5 settles default selection and operation naming. OD-6 settles absent +contributions, empty sequences, null, and kind mismatches. ### Mode Names And Effective-Identity Defaults @@ -447,13 +447,13 @@ This is an authoritative constraint, distinct from an application default that only fills an omission. Configuration can define identity for collections without an application-owned constraint. Omitted configuration identity uses a registered definition when present, and an explicit matching declaration is -accepted, as settled in OD-2. The final-result guarantee for -application-owned constraints is settled below; YAML-only enforcement remains -an open follow-up to OD-1. +accepted, as settled in OD-2. OD-1 below distinguishes the final-result guarantee +for application-owned constraints from assembly-time enforcement for YAML-only +declarations. ### Final-Result Guarantee For Application Registrations -**OD-1: settled for application-owned constraints.** +**OD-1: settled, including the YAML-only follow-up below.** > On successful loading, the final effective collections covered by application > registrations satisfy their declared identity constraints. @@ -466,8 +466,9 @@ does not require every intermediate callback state to satisfy the constraint and does not extend to caller mutations after loading returns. Keep the promise limited to the declared identity constraints. It does not by -itself require registered paths to exist or settle null and non-sequence -handling; those collection boundaries remain under OD-6. Final validation examines +itself require registered paths to exist or be non-null. Identity validation checks +actual sequences; the application schema and validation determine whether absence, +null, or another shape is acceptable, as settled in OD-6. Final validation examines effective typed values, while assembly-time checks retain their role in validating authored contributions. A final scalar value alone does not prove that the field was explicitly supplied in a source. @@ -477,7 +478,52 @@ provide the implementation foundation. Diagnostics should identify the affected collection and item paths, using available origin information without exposing identity values. The guarantee requires neither a new mutation-history system nor exact causal reconstruction for records supplied by defaults or callbacks. -Final enforcement for identities declared only in YAML is not settled here. + +### Assembly-Time Enforcement For YAML-Only Identities + +Enforce identities declared only in YAML during structural composition and +precedence assembly. They do not carry a final-result guarantee after later +defaulting, inheritance, CLI overrides, or application resolution. Those stages +may produce a collection that no longer satisfies a YAML-only identity, including +duplicate identities. OD-7 still owns whether any additional lifecycle stages +participate in the new combination operations. + +Applications requiring a final identity constraint register it through the +application-owned interface. This keeps YAML declarations aligned with the +structural operations they control and avoids extending their policy lifetime +through later replacements, callbacks, and nested-record changes solely for +final validation. + +### Absence, Empty Sequences, Null, And Kind Mismatches + +**OD-6: settled.** + +At a collection's precedence boundary: + +| Higher-tier 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; it does not erase records supplied elsewhere. +An absent lower collection can be initialized by an incoming sequence under +any mode, subject to identity requirements. An explicitly null or other +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. + +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. +Identity validation checks actual sequences; application schema and validation +own the permitted shape. Null as a collection is distinct from a present null +identity component inside a record, which is valid under OD-3. ## Architectural Direction @@ -518,42 +564,6 @@ design and test sequencing belong to that later plan. ## Open Decisions -### OD-1 Follow-Up. Final Validation For YAML-Only Identity Declarations - -Application-registered collections have the settled final-result guarantee -above. Should a configuration-only identity declaration carry the same -guarantee, or govern structural assembly alone? - -**Discussion basis:** Declaration scope and identity-policy lifetime are settled -in OD-2 and OD-3. Revisit final enforcement using the effective identity of each -retained collection. The application-owned guarantee remains independent of -this choice. - -**Alternatives:** Applying the same final check to YAML-declared identities -would give both declaration forms consistent enforcement, but requires carrying -the effective policy through later lifecycle stages, including nested records. -Limiting YAML-only identity to assembly keeps policy lifetime narrower, but later -operations could produce a final collection that no longer satisfies that -identity declaration. - -### OD-6. What Do Absence, Empty Sequences, And Null Mean? - -Can a declaration selecting nothing affect a lower collection? How do explicit -empty sequences, null, and non-sequence values interact with all three operations? - -**Initial recommendation:** An optional import selecting nothing contributes -nothing and does not clear lower values. An explicitly supplied empty sequence -with whole-sequence replacement can clear a collection; append or replacement -by identity with an empty sequence contributes no records. Preserve the -distinction between absence and supplied values. Decide -null and kind-mismatch handling explicitly rather than silently treating them -as empty sequences. - -**Alternative:** Treat an explicitly declared replacement operation as a reset -even when its import selects nothing. This provides a compact clearing mechanism, -but makes an optional missing file or empty search destructive. Keeping clearing -as an explicit value avoids that coupling. - ### OD-7. Which Lifecycle Stages Participate? Do the new cross-tier operations extend only source-backed tiers, or also