Settle sequence identity definitions and policy lifetime

This commit is contained in:
2026-10-22 13:28:18 +00:00
parent 86feb6d755
commit 6eb80b06e3

View File

@@ -45,6 +45,8 @@ later. Extending one does not automatically imply extending the other.
The proposed `configkit.sequences` block introduces a `key` declaration that The proposed `configkit.sequences` block introduces a `key` declaration that
accepts either one field or a list of fields for a compound identity. accepts either one field or a list of fields for a compound identity.
Fields are treated as a set; identity components may be strings, numbers,
booleans, or explicitly supplied null values.
Applications retain an optional interface for registering a collection Applications retain an optional interface for registering a collection
and imposing its identity definition. Configuration declarations must conform and imposing its identity definition. Configuration declarations must conform
to an application-owned constraint when one exists. The exact Go interface to an application-owned constraint when one exists. The exact Go interface
@@ -116,13 +118,13 @@ Identity and mode can be supplied independently. Omitted identity can use an
application registration; an explicit matching declaration is accepted, and a application registration; an explicit matching declaration is accepted, and a
conflicting declaration is invalid. Whole-sequence replacement does not itself conflicting declaration is invalid. Whole-sequence replacement does not itself
require identity matching, but application-owned constraints still apply. require identity matching, but application-owned constraints still apply.
Identity-policy lifetime across tiers remains under OD-3. Identity-policy lifetime across tiers is settled in OD-3 below.
Mode describes the current tier's combination instruction. A lower tier's Mode describes the current tier's combination instruction. A lower tier's
`append` does not silently select append for a later overlay. Gather collection `append` does not silently select append for a later overlay. Gather collection
declarations before composing their relevant scope so their effect does not declarations before composing their relevant scope so their effect does not
depend on which contribution is assembled first. Agreement and omission among depend on which contribution is assembled first. Identity agreement is settled
peer declarations remain under OD-4. in OD-3; operation agreement and omission among peers remain under OD-4.
Permit sequence declarations in selected overlays and make their use independent Permit sequence declarations in selected overlays and make their use independent
of filesystem import enablement. This deliberately changes the current blanket of filesystem import enablement. This deliberately changes the current blanket
@@ -185,6 +187,90 @@ inline/imported collections without duplicate authoring surfaces. Local wrappers
around sequence values would require distinguishing application data from around sequence values would require distinguishing application data from
control mappings; the existing reserved namespace keeps that distinction clear. control mappings; the existing reserved namespace keeps that distinction clear.
### Identity Definitions And Lifetime
**OD-3: settled.**
#### Field Sets
`key` accepts a string or a nonempty list of strings naming direct, literal
fields in each record. `key: id` and `key: [id]` are equivalent. A name such as
`metadata.id` denotes that literal field, not a nested lookup.
Treat the selected fields as a set: remove repeated names and disregard authored
field order when comparing definitions. For example, `[namespace, id]`,
`[id, namespace]`, and `[namespace, id, id]` define the same identity. An empty
list is invalid because it supplies no identity fields. These equivalence rules
also apply when comparing configuration declarations with application
registrations.
Use a consistent field order internally to construct compound identity tuples.
Preserve component types and tuple boundaries; concatenating unstructured values
must not cause otherwise distinct identities to collide.
#### Scalar Components And Equality
Each identified record must be a mapping, and every designated identity field
must be present. Components may be strings, numbers, booleans, or explicit null.
Missing fields and mapping or sequence components are invalid. A present null is
a valid component and is distinct from an absent field. Two single-field null
identities are equal; in a compound identity, all components must compare equal.
Strings compare exactly, with no trimming, case folding, or normalization.
Empty strings remain valid. Scalar categories remain distinct: the string
`"1"`, the number `1`, the boolean `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 comparison does not rewrite authored values or alter existing
typed decoding and projection semantics. The existing parser's rejection of
non-finite numeric forms remains unchanged.
#### Agreement And Introduction
Within a strict tier, identity declarations for the same collection must agree.
Equivalent field sets coalesce; different sets produce an error. Across tiers,
append and replacement by identity use one agreed definition for the records
being combined:
| Lower collection 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 identity definitions |
| None | `id` | Establish `id` and validate all participating records under it |
An application registration supplies identity when configuration omits it and
remains authoritative over explicit declarations. If neither the application nor
either participating collection supplies an identity, append and replacement by
identity fail; ConfigKit does not infer an `id` convention. Introducing identity
for a previously unkeyed lower sequence requires checking both lower and incoming
records, including uniqueness within each contribution.
#### Replacement And Policy Lifetime
YAML-owned identity follows the collection that survives an operation:
| Operation | Effective YAML-owned identity |
| --- | --- |
| Append | Retain or establish the agreed identity |
| Replacement by identity | Retain or establish the agreed identity |
| Whole-sequence replacement | Use the replacing tier's declaration and discard the lower collection's YAML-only identity |
Without an application constraint, whole-sequence replacement may introduce a
different identity, such as replacing an `id`-keyed collection with a `name`-keyed
collection. A whole-sequence replacement with no new identity declaration and no
application registration produces an unkeyed sequence. No separate identity
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.
### Whole-Record Replacement By Identity ### Whole-Record Replacement By Identity
The third cross-tier operation replaces each matching lower record with the The third cross-tier operation replaces each matching lower record with the
@@ -264,9 +350,9 @@ and does not extend to caller mutations after loading returns.
Keep the promise limited to the declared identity constraints. It does not by 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 itself require registered paths to exist or settle null and non-sequence
handling; those boundaries remain under OD-3 and OD-6. Final validation examines handling; those collection boundaries remain under OD-6. Final validation examines
effective typed values, while assembly-time checks retain their role in effective typed values, while assembly-time checks retain their role in
validating authored contributions. A final string value alone does not prove validating authored contributions. A final scalar value alone does not prove
that the field was explicitly supplied in a source. that the field was explicitly supplied in a source.
The existing canonical final-value representation and shared publication path The existing canonical final-value representation and shared publication path
@@ -286,16 +372,17 @@ The initial recommendation is to compose each tier's contributions strictly,
then apply one collection operation from the higher tier against the lower then apply one collection operation from the higher tier against the lower
sequence. A collection declaration would therefore govern its tier's contribution sequence. A collection declaration would therefore govern its tier's contribution
at that destination, without sequentially erasing peer contributions. Multiple at that destination, without sequentially erasing peer contributions. Multiple
agreeing declarations could coalesce; conflicting explicit identity or operation agreeing operation declarations could coalesce; conflicting explicit operations
declarations would produce errors. would produce errors. Identity declaration agreement is already settled in OD-3.
For append, the ordering recommendation is to retain lower-tier item order and For append, the ordering recommendation is to retain lower-tier item order and
then the higher tier's assembled item order. For replacement by identity, retain then the higher tier's assembled item order. For replacement by identity, retain
the position of each replaced record and append new identities in higher-tier the position of each replaced record and append new identities in higher-tier
order. Existing dependency-ready scheduling would continue to determine assembly order. Existing dependency-ready scheduling would continue to determine assembly
order within a tier. Whole-sequence replacement would retain only the higher order within a tier. Whole-sequence replacement would retain only the higher
tier's assembled sequence. Ordering and the treatment of peer declarations remain tier's assembled sequence. Ordering and the treatment of peer operation
recommendations awaiting agreement, not changes to the current ordering contract. declarations remain recommendations awaiting agreement, not changes to the
current ordering contract.
This requires collection policy to survive import expansion through precedence This requires collection policy to survive import expansion through precedence
assembly. Correctness includes final values, projected item paths, source assembly. Correctness includes final values, projected item paths, source
@@ -333,37 +420,17 @@ Application-registered collections have the settled final-result guarantee
above. Should a configuration-only identity declaration carry the same above. Should a configuration-only identity declaration carry the same
guarantee, or govern structural assembly alone? guarantee, or govern structural assembly alone?
**Initial recommendation:** With declaration scope settled in OD-2, resolve **Discussion basis:** Declaration scope and identity-policy lifetime are settled
identity-policy lifetime across replacement in OD-3 before this choice. Final in OD-2 and OD-3. Revisit final enforcement using the effective identity of each
enforcement needs an unambiguous effective policy for each retained collection. The retained collection. The application-owned guarantee remains independent of
application-owned guarantee can proceed independently of this choice. this choice.
**Alternatives:** Applying the same final check to YAML-declared identities **Alternatives:** Applying the same final check to YAML-declared identities
would give both declaration forms consistent enforcement, but requires resolving would give both declaration forms consistent enforcement, but requires carrying
which policy survives replacement or follows nested records. Limiting YAML-only the effective policy through later lifecycle stages, including nested records.
identity to assembly keeps policy lifetime narrower, but later operations could Limiting YAML-only identity to assembly keeps policy lifetime narrower, but later
produce a final collection that no longer satisfies that identity declaration. operations could produce a final collection that no longer satisfies that
identity declaration.
### OD-3. What Constitutes Identity, And When Can It Change?
Settle compound-key field selection, value types, missing/null components,
empty and repeated field lists, empty identity strings, and agreement between
declarations. Decide whether whole-sequence replacement can introduce a different identity
definition after discarding the lower collection when the application has imposed
no identity constraint. An application-owned constraint remains authoritative.
**Initial recommendation:** Interpret `key: id` as `[id]` and a compound key as
an ordered tuple of direct, literal string fields. Retain exact string comparison
and require every component to be present. Preserve tuple boundaries rather than
concatenating values. Identity declarations participating in append or replacement
by identity must agree; equal definitions within a scope coalesce and conflicting
definitions fail. Detailed list validation and identity changes at whole-sequence
replacement boundaries remain to be settled.
**Alternative:** Permit additional scalar types or nested field paths. These
support more schemas but add type-equality and addressing rules. A load-wide fixed
identity definition simplifies agreement across tiers; allowing a replacement to
establish a new definition gives independently authored layers more flexibility.
### OD-4. What Does A Combination Choice Control? ### OD-4. What Does A Combination Choice Control?