Reconcile sequence identity documentation

This commit is contained in:
2026-10-23 21:57:35 +00:00
parent d4133f23f5
commit e01aeca761
12 changed files with 239 additions and 260 deletions

View File

@@ -27,12 +27,14 @@ the [configuration contract](docs/config.md#effective-configuration-diffs) and
[consumer guide](docs/consumers/README.md#effective-configuration-diffs) describe [consumer guide](docs/consumers/README.md#effective-configuration-diffs) describe
its safe changed-region records and maintained workflows. its safe changed-region records and maintained workflows.
Sources can also be explicitly placed as sequence items, and definitions can Sources can also be explicitly placed as sequence items. Configuration
register selected sequences to append records with distinct string IDs during declarations and application registrations can give selected sequences scalar
strict composition. Higher-priority sequences still replace lower-priority identities and choose how they combine across precedence and inheritance.
sequences as whole values. See the [sequence contract](docs/config.md#strict-document-composition), Strict peers combine distinct records, while higher-priority collections can
[maintained prompt example](docs/consumers/README.md#identified-prompt-sequences), replace, append, or upsert whole records. See the
and [ADR 0014](docs/adr/0014-sequence-placement-and-composition.md). [sequence contract](docs/config.md#strict-document-composition),
[maintained catalog examples](docs/consumers/README.md#identified-prompt-sequences),
and [ADR 0017](docs/adr/0017-collection-sequence-policy.md).
Imports are also explicit: a source may name files, search declared directories, Imports are also explicit: a source may name files, search declared directories,
or select files with path globs. Applications can set load-wide import defaults or select files with path globs. Applications can set load-wide import defaults
@@ -78,12 +80,12 @@ precedence tiers, mappings combine recursively, retaining omitted lower-priority
children; other values replace lower-priority values. The main document and its children; other values replace lower-priority values. The main document and its
imports form one strictly composed tier. Explicit underlay groups sit below it imports form one strictly composed tier. Explicit underlay groups sit below it
and above typed defaults; a selected overlay applies before inheritance, while and above typed defaults; a selected overlay applies before inheritance, while
explicit CLI overrides apply to the decoded configuration before application explicit CLI overrides apply after decoding and before application resolution.
resolution. The [configuration contract](docs/config.md#strict-document-composition) The [configuration contract](docs/config.md#strict-document-composition) owns
owns the detailed combination rules and input-specific constraints. At the detailed combination rules and input-specific constraints. Declared or
definition-registered paths only, strict composition can append records with registered collections combine distinct identified records within strict tiers
distinct explicit IDs; ordinary and unregistered sequences keep their conflict and use their selected operation at precedence boundaries; other sequences keep
or whole-value replacement behavior. their strict-conflict and whole-value-replacement behavior.
The [architecture goals](docs/policy/architecture.md#success-criteria) explain The [architecture goals](docs/policy/architecture.md#success-criteria) explain
these priorities and how genuine new needs can justify extending the shared these priorities and how genuine new needs can justify extending the shared

View File

@@ -138,6 +138,6 @@ Record inheritance also requires parent lookup by identity and checking for
missing parents and cycles. Copied settings retain the same source, history, missing parents and cycles. Copied settings retain the same source, history,
and sensitivity information as mapping-sibling inheritance. and sensitivity information as mapping-sibling inheritance.
The configuration contract will define declaration syntax, identity comparison, The [configuration contract](../config.md#strict-document-composition) defines
omission and empty-value behavior, and diagnostics when the feature is declaration syntax, identity comparison, omission and empty-value behavior, and
implemented. diagnostics for the implemented feature.

View File

@@ -80,5 +80,5 @@ must remain consistent throughout loading.
CLI input can no longer add or cancel inheritance relationships or bypass an CLI input can no longer add or cancel inheritance relationships or bypass an
earlier error in source assembly or inheritance. It also cannot fix a value that earlier error in source assembly or inheritance. It also cannot fix a value that
fails the earlier decoding step. Semantic validation still runs after overrides fails the earlier decoding step. Semantic validation still runs after overrides
and application resolution. The configuration contract and consumer guidance and application resolution. The [configuration contract](../config.md#explicit-cli-overrides)
must explain these behavior changes when they are implemented. and [consumer guidance](../consumers/README.md) describe this behavior.

View File

@@ -814,9 +814,10 @@ validated, but there are no imported peers to combine.
| Any other pair of present nodes | Any other pair of present nodes | `compose.conflict` | | Any other pair of present nodes | Any other pair of present nodes | `compose.conflict` |
Every non-mapping overlap is a conflict, even when values are equal, except for Every non-mapping overlap is a conflict, even when values are equal, except for
sequence/sequence contributions at a registered sequence identity destination sequence/sequence contributions at a destination with effective identity from an
or a source-declared collection destination. Nulls remain atomic conflicts. application registration, a current YAML `key` declaration, or retained lower
Unregistered and undeclared sequences conflict when repeated and are never joined policy. Nulls remain atomic conflicts.
Sequences without effective identity conflict when repeated and are never joined
by index. Disjoint entries under shared mappings compose, making stable keyed by index. Disjoint entries under shared mappings compose, making stable keyed
mappings the natural representation for independently contributed entries. mappings the natural representation for independently contributed entries.
@@ -827,44 +828,49 @@ segments created by `SequenceLiteralKey` and `SequenceAnyMappingKey`. A literal
`"*"` key is distinct from the wildcard constructor. Parsed numeric path tokens `"*"` key is distinct from the wildcard constructor. Parsed numeric path tokens
remain literal mapping keys; explicit index segments and reserved `configkit` or remain literal mapping keys; explicit index segments and reserved `configkit` or
mapping-valued `extends` segments are invalid. The root selector is harmless under mapping-valued `extends` segments are invalid. The root selector is harmless under
the mapping-root schema. Each registration requires one or more literal field the mapping-root schema. Selector segments consume one mapping level and match a
names; compound field sets are normalized as sets, and field names are not complete destination; an any-mapping-key segment matches exactly one key, not an
otherwise normalized. arbitrary prefix or suffix. Each registration requires one or more literal,
direct field names; compound field sets are normalized as sets, and field names
are not otherwise normalized. The same field-set and scalar-equality rules apply
to YAML `key` declarations.
At each selected path, records must provide every registered field as a scalar At each selected path, records must provide every effective identity field as a
string, number, boolean, or explicit null. The type-tagged tuple preserves scalar string, number, boolean, or explicit null. Field names form a set, so
category distinctions, while equivalent finite decimal spellings such as `1`, order and repetition do not affect compound identity. The type-tagged tuple
`1.0`, and `1e0` compare as the same number. Distinct tuples append in source and preserves category distinctions: strings compare exactly, including empty
list order; duplicate tuples conflict even when records are otherwise equal or strings; numbers, booleans, and null remain distinct categories. Finite numbers
disjoint. Malformed records produce `compose.invalid`; duplicate identities compare by exact mathematical value, so `1`, `1.0`, and `1e0` are equal, as are
`0` and `-0`, without floating-point rounding. Distinct tuples append in source
and list order; duplicate tuples conflict even when records are otherwise equal
or disjoint. Malformed records produce `compose.invalid`; duplicate identities
produce `compose.conflict`, with paths and source locations identifying a produce `compose.conflict`, with paths and source locations identifying a
duplicate without exposing identity values. Missing paths and non-sequence values duplicate without exposing identity values. Missing paths and non-sequence values
do not fail by themselves. Equivalent overlapping registrations coalesce; do not fail by themselves. Equivalent overlapping registrations coalesce.
incompatible overlaps and invalid registrations produce `options.invalid` before Incompatible overlaps and invalid registrations produce `options.invalid` before
source acquisition. Unused and root registrations are allowed and have no effect. source acquisition. Unused and root registrations are allowed and have no effect.
Registration controls strict composition and supplies identity fields for parent Registrations provide identity for strict composition, sequence operations,
lookup when surviving records in that sequence use `extends`. Dynamic selectors inheritance lookup, and final validation. Dynamic selectors apply at concrete
apply at strict-composition and inheritance destinations without requiring the strict-composition, inheritance, and final-result destinations without requiring
application to enumerate mapping keys. Each underlay group and the main tier has the application to enumerate mapping keys. Each strict tier has independent
independent duplicate-identity state. Precedence assembly is unchanged: a present duplicate-identity state among its peers; layered precedence and inheritance
higher-priority sequence replaces the lower sequence as one value, including at a then apply the collection operation described below.
registered path.
After effective secret lookup, the shared load lifecycle validates every matching Final registration checks run in both ordinary and layered loads after effective
sequence in the final typed projection before application semantic validation. secret lookup and before application semantic validation. They examine actual
This catches identities introduced by typed defaults, CLI assignment, or recorded final typed sequences, including values introduced by defaults, CLI, or recorded
resolution, in both ordinary and layered loads. Only actual sequences are checked; resolution; they do not require path existence or sequence shape. Diagnostics
absent paths and other shapes remain the schema or application validator's concern. use concrete collection and item paths and available source locations, without
Identity fields are read from effective typed payload regardless of authored exposing identity or credential values. The guarantee ends when loading publishes
presence. Diagnostics use concrete collection and item paths and available source successfully and does not cover later caller mutations.
locations, and never include identity or credential values. The guarantee ends at YAML-only identity is enforced during structural composition, precedence, and
successful publication; later caller mutations are outside it. The accepted identified inheritance; it carries no final-result guarantee after typed
rationale is recorded in defaults, CLI, or application resolution. Applications that need that guarantee
[ADR 0014](adr/0014-sequence-placement-and-composition.md). register the identity constraint.
The [maintained prompt catalog](consumers/README.md#identified-prompt-sequences) The [maintained catalog examples](consumers/README.md#identified-prompt-sequences)
shows item path and glob imports, helper-supplied identity, and main-tier show strict peers, precedence operations, inheritance, dynamic destinations, and
replacement of a lower-priority sequence. the distinction between YAML-only declarations and application registrations.
When an enabled source-version mode is selected, declarations are checked in each When an enabled source-version mode is selected, declarations are checked in each
source's own coordinates before placement and composition. Accepted non-main source's own coordinates before placement and composition. Accepted non-main
headers are consumed before strict composition and cannot supply a registered headers are consumed before strict composition and cannot supply a registered
@@ -872,34 +878,74 @@ record identity. Final typed decoding and application validation still run on th
completed configuration. completed configuration.
Ordinary sources, layered inputs, and selected overlays may declare collection Ordinary sources, layered inputs, and selected overlays may declare collection
behavior under `configkit.sequences` at the document root. Each entry has a required literal behavior under `configkit.sequences` at the document root. Each entry has a
`destination` and may specify `key` as one string or a nonempty list of strings, required literal `destination` and may specify `key` as one string or a nonempty
plus a `mode` of `replace`, `append`, or `upsert`. These controls are removed list of strings, plus a `mode` of `replace`, `append`, or `upsert`. These
before application decoding. A declaration destination is relative to that controls are removed before application decoding. A declaration destination is
source's placement, so a mounted fragment's declaration is mounted with its relative to that source's placement, so a mounted fragment's declaration is
values. Declarations from mounted with its values. Declarations from strict peers must agree on identity
strict peers must agree on identity fields and on any explicitly supplied mode; fields and on any explicitly supplied mode; omission expresses no mode
they apply even when the declaring source has no value at that destination. preference. They apply even when the declaring source has no value at that
Singleton sequence contributions are validated as well as peers. A key supplies destination: a key validates an existing retained sequence or remains pending
the identity used by `append` and `upsert`; without an explicit or retained mode, until records arrive, while a mode-only declaration affects later combinations
a keyed collection uses `upsert`, while an unkeyed collection uses `replace`. without recombining earlier tiers. A key supplies the identity used by `append`
`append` keeps contribution order and rejects repeated identities. `upsert` and `upsert` and is checked against any application registration.
replaces a complete matched record at its existing position and appends new
identities in incoming order; it does not merge record fields. Strict peers at an identified destination first combine distinct records in
source and list order. Duplicate identities among peers or within one
contribution fail under every mode. After strict composition, precedence and
inheritance use one operation for the assembled incoming collection:
| 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 at their lower positions, retain unmatched lower records, and append new identities. |
Upsert replaces the complete matched record; it does not recursively merge
record fields. Append and upsert require identity. With no explicit mode in the
current tier, an explicit lower mode persists; if none exists, effective identity
selects upsert and its absence selects replace. Inferred modes do not persist.
Explicit modes persist at their destination until changed by a higher explicit
mode, independently of YAML identity lifetime. A declaration alone does not
clear or recombine a collection.
The presence and value kind at a precedence or inheritance boundary determine
whether a collection changes:
| 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 | Replace the lower value, subject to application schema. | Error; the operation requires a sequence. |
An absent lower value can be initialized by an incoming sequence under any mode.
A present lower null or other non-sequence value is not absence: append and
upsert cannot combine with it. An empty sequence still requires a valid mode and
identity where applicable. Null used as an identity component inside a record is
distinct from null used as the collection value.
Declarations govern ordinary strict source composition, including loads with Declarations govern ordinary strict source composition, including loads with
imports disabled, and each strict scope in layered loading. Layered groups and imports disabled, and each strict scope in layered loading. Before composing a
main apply their resolved sequence operation between precedence tiers; a higher higher tier's peers, ConfigKit makes applicable lower identity and explicit mode
strict scope inherits the lower identity and explicit mode before peer available; after peer composition, the tier applies its resolved operation
composition. Overlay declarations apply after the base source graph is composed against the lower collection. Selected overlays use the same collection policy
and must agree with retained collection identity and any application after the base source graph is composed. During mapping-sibling inheritance, a
registration. During mapping-sibling inheritance, a parent's YAML identity can parent's YAML identity can follow its collection to the child destination, while
follow its collection to the child destination, while the parent's explicit the parent's explicit operation stays at the parent destination. The child
operation stays at the parent destination. A child declaration selects the destination selects its operation; absent one, effective identity implies
operation at its destination; absent one, keyed collections use upsert and upsert and its absence implies replace. Whole-sequence replacement discards
unkeyed collections use replace. These policies do not change CLI behavior. A root lower YAML identity and uses the replacing scope's key declaration, if any;
`configkit.imports` declaration still requires `Options.Imports`; `NoSource` has without one, the collection is unkeyed unless an application registration still
no declaration scope. supplies identity. Replacement discards policies owned by removed records, while
an independently declared explicit mode and application registration remain
applicable. Item-local
policies follow their owning records: retaining a record retains its rules, while
whole-record upsert replacement discards the displaced record's rules. Matching
identity or reusing an index does not transfer them. These policies do not change
CLI behavior: CLI sequence assignments replace whole sequences after decoding.
A root `configkit.imports` declaration still requires `Options.Imports`;
`NoSource` has no declaration scope.
An empty mapping contributes no child definitions. Two empty mappings compose, and An empty mapping contributes no child definitions. Two empty mappings compose, and
an empty mapping neither clears nor conflicts with another mapping's children. an empty mapping neither clears nor conflicts with another mapping's children.
@@ -1076,6 +1122,12 @@ filenames unrestricted; a non-nil empty slice selects none. Defaults do not make
a field applicable to selectors that do not support it, and load calls snapshot a field applicable to selectors that do not support it, and load calls snapshot
the supplied pointers and slice before source acquisition. the supplied pointers and slice before source acquisition.
A source's `configkit.sequences` declarations apply independently of import
enablement; a `configkit.imports` declaration still requires `Options.Imports`.
Sequence identities can be supplied either by these YAML declarations or by
application registrations. The [strict composition contract](#strict-document-composition)
defines their agreement, operation, and lifetime rules.
Acquisition visits declarations in authored order and each declaration's selected Acquisition visits declarations in authored order and each declaration's selected
paths in namespace-path lexical order, preserving source-record and version-callback paths in namespace-path lexical order, preserving source-record and version-callback
order. Ordinary mapping contributions in a main tier are assembled dependency-first: order. Ordinary mapping contributions in a main tier are assembled dependency-first:
@@ -1087,9 +1139,10 @@ mapping scope, with helpers before the bodies that import them. Those local scop
do not use application collection policies and are not flattened into the outer do not use application collection policies and are not flattened into the outer
schedule. Item positions and diagnostic paths follow the resulting assembly order. schedule. Item positions and diagnostic paths follow the resulting assembly order.
Each underlay group likewise acquires its inputs before dependency-ready assembly Each underlay group likewise acquires its inputs before dependency-ready assembly
in one strict scope. Independent groups remain separate precedence tiers; a higher in one strict scope. Independent groups remain separate precedence tiers; at a
tier still replaces a lower tier's sequence values wholesale. Assembly order never declared or registered destination, the assembled higher sequence uses the
permits replacement. resolved collection operation against the lower sequence. Other sequences retain
whole-value replacement between tiers. Assembly order never permits replacement.
Acquisition order and resolution order serve different purposes: acquisition Acquisition order and resolution order serve different purposes: acquisition
assigns source records and callback order, while the shared scheduler determines assigns source records and callback order, while the shared scheduler determines
@@ -1120,13 +1173,17 @@ Each declaration may include `placement: mapping` or
including every match of a glob; placement is not inherited. Sequence-item including every match of a glob; placement is not inherited. Sequence-item
placement requires a nonempty effective destination and wraps the imported placement requires a nonempty effective destination and wraps the imported
mapping as one element of a sequence there. It does not split source sequences mapping as one element of a sequence there. It does not split source sequences
or infer identity fields. Repeated sequences still conflict unless their path is or infer identity fields. Repeated sequences combine only when the destination
registered through `Definition.SequenceIdentities`; registration does not has an applicable YAML identity declaration or application registration; source
change placement or precedence behavior. Sequence records retain source placement remains independent of collection identity and operation. Sequence
locations through placement and history; indexes describe their assembled records retain source locations through placement and history; indexes describe
positions while source coordinates continue to identify the declaring files. their assembled positions while source coordinates continue to identify the
Header/version policy and final application validation retain their existing declaring files.
owners and timing; sequence registration is a strict-composition rule only. Header/version policy retains its existing owner and timing. Application
registrations also enforce identity on the final effective typed configuration;
YAML-only declarations are enforced at structural combination and inheritance
boundaries. The [configuration contract](#strict-document-composition) defines
these validation boundaries.
An item import first opens a local mapping scope. Its body and ordinary helper An item import first opens a local mapping scope. Its body and ordinary helper
imports compose within that record. An omitted helper destination or imports compose within that record. An omitted helper destination or

View File

@@ -21,7 +21,7 @@ sanitized shapes using only ConfigKit and the Go standard library:
| Named presets | One-load sibling inheritance, explicit false, nested destination resolution, and source/derivation inspection | Choosing and executing a preset | | Named presets | One-load sibling inheritance, explicit false, nested destination resolution, and source/derivation inspection | Choosing and executing a preset |
| Effective configuration diff | Same-type frozen effective comparisons for two selected files or base-versus-overlay impact | Source/options selection and consumer-owned safe presentation | | Effective configuration diff | Same-type frozen effective comparisons for two selected files or base-versus-overlay impact | Source/options selection and consumer-owned safe presentation |
| Shared source-version checks | One `Definition.Version` policy for accepted declarations across participating source documents, with optional or required declarations and sanitized evidence | Choosing which declarations the application accepts; final assembled schema and domain validation | | Shared source-version checks | One `Definition.Version` policy for accepted declarations across participating source documents, with optional or required declarations and sanitized evidence | Choosing which declarations the application accepts; final assembled schema and domain validation |
| Identified prompt sequences | Explicit item path/glob imports, helper-supplied IDs, reusable single-field registration, same-sequence record inheritance, and main-tier replacement of a lower-priority collection | Prompt meaning and final domain validation | | Sequence catalogs | Declared collection operations, record inheritance, typed CLI and resolution, inspection, exact and wildcard application registrations | Catalog meaning and final domain validation |
The YAML under [`testdata`](../../examples/consumers/testdata) is loaded by the The YAML under [`testdata`](../../examples/consumers/testdata) is loaded by the
executable examples and ordinary tests. It contains no private application data, executable examples and ordinary tests. It contains no private application data,
@@ -184,43 +184,35 @@ import, source-location, and ownership behavior.
## Identified prompt sequences ## Identified prompt sequences
[`LoadPromptCatalog`](../../examples/consumers/prompt_catalog.go) uses one [`LoadPromptCatalog`](../../examples/consumers/prompt_catalog.go) shows the
definition registration for the literal `prompts` path and `id` field. Its smaller import-focused adoption path: a registered `prompts.id` identity,
load-wide filename defaults accept two patterns, an explicit directory directory and glob selection, a helper import that supplies an item's ID, and
declaration overrides those patterns, and an exclusion omits one matching resource lookup through the effective source context. Its executable examples
candidate. A nested ordinary helper import supplies an item's ID. A separate and tests are in
empty optional directory search is read from `SourceInfo.ImportSelections`. [`prompt_catalog_test.go`](../../examples/consumers/prompt_catalog_test.go), with
The executable example prints both the scheduled prompt order and the single complete [catalog](../../examples/consumers/testdata/prompt-catalog/config.yml)
empty-search outcome; the behavior test also follows a mounted resource through and [required-file](../../examples/consumers/testdata/prompt-catalog/simple.yml)
its effective metadata origin to the declaring source context. The completed fixtures.
main sequence replaces the lower-priority default collection as one value.
The maintained [executable example and behavior tests](../../examples/consumers/prompt_catalog_test.go)
show the scheduled result, empty-search inspection, excluded candidate, and
resource lookup without a consumer-side discovery pass. The corresponding
[complex fixture](../../examples/consumers/testdata/prompt-catalog/config.yml)
and [simple required-file fixture](../../examples/consumers/testdata/prompt-catalog/simple.yml)
are complete local examples.
[`LoadRequiredPromptCatalog`](../../examples/consumers/prompt_catalog.go) and [`LoadSequenceCatalog`](../../examples/consumers/sequence_catalog.go) integrates
[`Example_requiredPromptCatalog`](../../examples/consumers/prompt_catalog_test.go) an underlay declaration, imported main fragments, identified-record inheritance,
keep the smaller adoption path visible: one explicitly required file import, selected overlay `append`, `upsert`, and `replace`, a typed CLI override, and
the same identity registration, and the same application validation. recorded application resolution. Its tests and runnable example demonstrate
stable output order, whole-record upsert, provenance/history inspection,
resource lookup for inherited records, and secret-safe explanation in
[`sequence_catalog_test.go`](../../examples/consumers/sequence_catalog_test.go).
[`LoadNamespacedMapCatalog`](../../examples/consumers/sequence_catalog.go) adds
an exact root registration and a wildcard namespace registration, showing that
each concrete sequence has an independent identity scope. The same tests show
that a YAML identity declaration without an application registration does not
create final-result identity enforcement.
The registered `id` also identifies surviving prompt records that use The examples keep prompt meaning and domain checks in the consuming application.
`extends: {id: "base-id"}`. ConfigKit resolves these references within the The [configuration contract](../config.md#strict-document-composition) owns
completed prompt sequence after tier assembly, preserves the child's own ID, and declaration, identity, operation, ownership, and final-validation semantics;
records inherited values at the child's paths. The [sibling inheritance](../config.md#sibling-inheritance) defines record
[configuration contract](../config.md#sibling-inheritance) defines the exact relationships, and the [CLI contract](../config.md#explicit-cli-overrides) owns
reference and nested collection behavior. override ordering.
The example's `validatePromptCatalog` remains application-owned. It checks that
prompt names and message lists satisfy this consumer's requirements after
ConfigKit has composed, inherited, projected, and decoded the configuration.
ConfigKit does not apply identity-based overlays or enforce final uniqueness
after defaults and resolution. See the [strict composition contract](../config.md#strict-document-composition),
[import syntax](../config.md#explicit-imports), and
[ADR 0014](../adr/0014-sequence-placement-and-composition.md) for the exact
boundaries.
Known module catalogs should use canonical object entries with a module identifier Known module catalogs should use canonical object entries with a module identifier
and typed options. A small union struct is sufficient when the available option and typed options. A small union struct is sufficient when the available option

View File

@@ -135,12 +135,13 @@ Current behavior belongs to the configuration contract's
[input destinations](config.md#input-destinations), [input destinations](config.md#input-destinations),
[imports](config.md#explicit-imports), and [imports](config.md#explicit-imports), and
[shared source-version checks](config.md#shared-source-version-checks) sections. [shared source-version checks](config.md#shared-source-version-checks) sections.
Explicit sequence-item placement and registered strict composition are owned by Explicit sequence-item placement, collection operations, identity registration,
the [strict composition](config.md#strict-document-composition) and and final registered-identity validation are owned by the
[imports](config.md#explicit-imports) sections. The [strict composition](config.md#strict-document-composition) section;
[maintained prompt catalog](consumers/README.md#identified-prompt-sequences) [imports](config.md#explicit-imports) owns acquisition and scheduling. The
shows the current consumer boundary, and [ADR 0014](adr/0014-sequence-placement-and-composition.md) [maintained sequence catalog](consumers/README.md#identified-prompt-sequences)
records the decision. shows the consumer boundary, and [ADR 0017](adr/0017-collection-sequence-policy.md)
records the collection decision.
The completed sequence-composition roadmap, implementation plan, and resolved The completed sequence-composition roadmap, implementation plan, and resolved
remediation record are preserved in Git history at `008d2ba` under remediation record are preserved in Git history at `008d2ba` under
@@ -218,6 +219,7 @@ code changes. Use the component overview to find the corresponding implementatio
| Import defaults, empty-selection evidence, and dependency-ready ordering | [Defaults and facade evidence](../facade_import_defaults_test.go), [engine import evidence](../internal/engine/import_evidence_test.go), [scheduler](../internal/engine/dependency_order_test.go), [scheduling integrations](../internal/engine/imports_test.go) | `go test ./internal/engine -run 'Import|ScheduleDependencies|Inheritance'`, `go test . -run 'ImportDefaults|FacadeImport'`, and `go test ./examples/consumers` | | Import defaults, empty-selection evidence, and dependency-ready ordering | [Defaults and facade evidence](../facade_import_defaults_test.go), [engine import evidence](../internal/engine/import_evidence_test.go), [scheduler](../internal/engine/dependency_order_test.go), [scheduling integrations](../internal/engine/imports_test.go) | `go test ./internal/engine -run 'Import|ScheduleDependencies|Inheritance'`, `go test . -run 'ImportDefaults|FacadeImport'`, and `go test ./examples/consumers` |
| Native filesystem and mapping sources | [Native acquisition](../internal/engine/native_filesystem_test.go), [filesystem facade](../facade_filesystem_test.go), [mapping facade](../facade_mapping_test.go) | `go test ./internal/engine -run 'NativeFilesystem'` and `go test . -run 'TestFacade'` | | Native filesystem and mapping sources | [Native acquisition](../internal/engine/native_filesystem_test.go), [filesystem facade](../facade_filesystem_test.go), [mapping facade](../facade_mapping_test.go) | `go test ./internal/engine -run 'NativeFilesystem'` and `go test . -run 'TestFacade'` |
| Composition, selected overlays, CLI precedence | [Composition](../internal/engine/compose_test.go), [overlay](../internal/engine/overlay_test.go), [selected overlays](../internal/engine/selected_overlay_test.go), [overrides](../internal/engine/override_test.go) | `go test ./internal/engine -run 'Compose\|Overlay\|Override'` | | Composition, selected overlays, CLI precedence | [Composition](../internal/engine/compose_test.go), [overlay](../internal/engine/overlay_test.go), [selected overlays](../internal/engine/selected_overlay_test.go), [overrides](../internal/engine/override_test.go) | `go test ./internal/engine -run 'Compose\|Overlay\|Override'` |
| Sequence identity, declarations, and operations | [Identity](../internal/engine/sequence_identity_test.go), [registrations](../internal/engine/sequence_registration_test.go), [declarations](../internal/engine/sequence_declaration_test.go), [combination](../internal/engine/sequence_combine_test.go), [final facade validation](../facade_final_sequence_identity_test.go), and [consumer catalog](../examples/consumers/sequence_catalog_test.go) | `go test ./internal/engine -run 'Sequence\|Collection'`, `go test . -run 'SequenceIdentity\|SequenceRegistration'`, and `go test ./examples/consumers` |
| Sibling inheritance, provenance, history, sensitivity | [Expansion](../internal/engine/inheritance_test.go), [destination scopes](../internal/engine/inheritance_walk_test.go), [origins](../internal/engine/inheritance_origin_test.go), [history](../internal/engine/inheritance_history_test.go), [secrets](../internal/engine/inheritance_secret_test.go), [public loading](../facade_inheritance_test.go) | `go test ./internal/engine -run 'Inheritance\|Inherited'` and `go test . -run '^TestFacadeInheritance\|^TestFacadeInheritedSecrets'` | | Sibling inheritance, provenance, history, sensitivity | [Expansion](../internal/engine/inheritance_test.go), [destination scopes](../internal/engine/inheritance_walk_test.go), [origins](../internal/engine/inheritance_origin_test.go), [history](../internal/engine/inheritance_history_test.go), [secrets](../internal/engine/inheritance_secret_test.go), [public loading](../facade_inheritance_test.go) | `go test ./internal/engine -run 'Inheritance\|Inherited'` and `go test . -run '^TestFacadeInheritance\|^TestFacadeInheritedSecrets'` |
| Layered loading and source equivalence | [Grouped lifecycle](../internal/engine/load_request_test.go), [layered facade](../facade_layered_test.go), [equivalence](../facade_equivalence_test.go) | `go test ./internal/engine -run '^TestGrouped'`, `go test . -run '^TestFacadeLayered'`, and `go test . -run '^TestEquivalentSourceForms'` | | Layered loading and source equivalence | [Grouped lifecycle](../internal/engine/load_request_test.go), [layered facade](../facade_layered_test.go), [equivalence](../facade_equivalence_test.go) | `go test ./internal/engine -run '^TestGrouped'`, `go test . -run '^TestFacadeLayered'`, and `go test . -run '^TestEquivalentSourceForms'` |
| Input and relative-import destinations, mounted sources, and source ownership | [Destination engine tests](../internal/engine/destination_test.go), [tier tests](../internal/engine/destination_tiers_test.go), [import traversal and version tests](../internal/engine/destination_import_test.go), [accounting tests](../internal/engine/destination_accounting_test.go), [lifecycle inspection tests](../internal/engine/destination_import_lifecycle_test.go), [public source/error tests](../facade_destination_test.go), [resource contexts](../facade_resource_context_test.go), and [consumer examples](../examples/consumers/destinations_test.go) | `go test ./internal/engine -run 'Destination|Import|Glob|Mounted'`, `go test . -run 'Destination|Import|SourceContext|FacadeMounted'`, and `go test ./examples/consumers` | | Input and relative-import destinations, mounted sources, and source ownership | [Destination engine tests](../internal/engine/destination_test.go), [tier tests](../internal/engine/destination_tiers_test.go), [import traversal and version tests](../internal/engine/destination_import_test.go), [accounting tests](../internal/engine/destination_accounting_test.go), [lifecycle inspection tests](../internal/engine/destination_import_lifecycle_test.go), [public source/error tests](../facade_destination_test.go), [resource contexts](../facade_resource_context_test.go), and [consumer examples](../examples/consumers/destinations_test.go) | `go test ./internal/engine -run 'Destination|Import|Glob|Mounted'`, `go test . -run 'Destination|Import|SourceContext|FacadeMounted'`, and `go test ./examples/consumers` |

View File

@@ -65,11 +65,18 @@ returns a closed cycle rotated to its smallest key; blocked dependents are not
reported as cycle members. reported as cycle members.
Import composition schedules a main tier or one underlay group as a single Import composition schedules a main tier or one underlay group as a single
strict-scope graph. Item contributions own nested local strict-mapping scopes; strict-scope graph. Applicable collection declarations are gathered for the
their helpers complete before the item is placed in its outer scope. Inheritance scope before peer composition, including identity inherited from lower tiers.
uses the same ready-node rule inside each sibling mapping scope, while preserving Identified peer sequences then combine distinct records in assembled source and
the authored mapping order in its output. These scopes do not flatten into one list order; after the strict scope completes, layered assembly applies the
global graph, and independent precedence tiers remain separate. resolved collection operation against the lower value, as defined by the
[configuration contract](../config.md#strict-document-composition). Item
contributions own nested local strict-mapping scopes; their helpers complete
before the item is placed in its outer scope. Inheritance uses the same
ready-node rule inside each sibling mapping scope, while preserving the authored
mapping order in its output.
These scopes do not flatten into one global graph, and independent precedence
tiers remain separate.
The main owners are [`import_selection.go`](../../internal/engine/import_selection.go), The main owners are [`import_selection.go`](../../internal/engine/import_selection.go),
[`directory_walk.go`](../../internal/engine/directory_walk.go), [`directory_walk.go`](../../internal/engine/directory_walk.go),

View File

@@ -9,12 +9,13 @@ Implemented component owners:
- `internal/engine` owns host and native-filesystem source acquisition, - `internal/engine` owns host and native-filesystem source acquisition,
grouped strict composition, recursive precedence assembly, per-input mapping grouped strict composition, recursive precedence assembly, per-input mapping
and sequence-item placement, definition-registered distinct-ID sequence and sequence-item placement, YAML collection declarations and operations for
composition within strict tiers, and immediate-parent-relative import identified sequences, and application identity registrations for strict
placement within that assembly. Higher-priority sequences replace lower composition, inheritance, and final validation. It applies the selected
sequences as whole values. The engine also owns dependency-ready, collection operation at precedence boundaries and owns dependency-ready,
destination-local sibling inheritance before typed decoding, plus shared destination-local inheritance before typed decoding. CLI assignment follows
source-version checking with sanitized declaration evidence. inheritance and decoding, before application resolution. The engine also owns
shared source-version checking with sanitized declaration evidence.
Explicit import discovery supports declared paths, directory searches, and Explicit import discovery supports declared paths, directory searches, and
globs; load-wide defaults and source-local empty-selection evidence cross the globs; load-wide defaults and source-local empty-selection evidence cross the
root facade without changing acquisition order. Import and inheritance root facade without changing acquisition order. Import and inheritance
@@ -56,9 +57,10 @@ semantics, including [input destinations](../config.md#input-destinations),
[shared source-version checks](../config.md#shared-source-version-checks), and [shared source-version checks](../config.md#shared-source-version-checks), and
[effective configuration diffs](../config.md#effective-configuration-diffs). [effective configuration diffs](../config.md#effective-configuration-diffs).
The [strict composition contract](../config.md#strict-document-composition) The [strict composition contract](../config.md#strict-document-composition)
owns sequence placement, registration, replacement, and history behavior; the owns sequence declarations, identity, operations, ownership, and final
[consumer guide](../consumers/README.md#identified-prompt-sequences) shows the validation; [CLI overrides](../config.md#explicit-cli-overrides) own override
maintained example. ordering. The [consumer guide](../consumers/README.md#identified-prompt-sequences)
links maintained workflow examples.
The [consumer adoption guide](../consumers/README.md) owns application guidance. The [consumer adoption guide](../consumers/README.md) owns application guidance.
The [architecture policy](../policy/architecture.md) owns contributor The [architecture policy](../policy/architecture.md) owns contributor
boundaries; [ADR 0006](../adr/0006-public-facade.md) records the facade decision boundaries; [ADR 0006](../adr/0006-public-facade.md) records the facade decision
@@ -74,5 +76,7 @@ records the source-version decision.
sequence placement and composition. [ADR 0015](../adr/0015-shared-dependency-ready-ordering.md) sequence placement and composition. [ADR 0015](../adr/0015-shared-dependency-ready-ordering.md)
records the shared dependency-ready ordering decision; [ADR records the shared dependency-ready ordering decision; [ADR
0016](../adr/0016-independent-import-controls.md) records the independent 0016](../adr/0016-independent-import-controls.md) records the independent
selection controls. The [import internals](imports.md) document candidate and selection controls. [ADR 0017](../adr/0017-collection-sequence-policy.md) and
[ADR 0018](../adr/0018-cli-after-structural-resolution.md) record collection
operations and CLI ordering. The [import internals](imports.md) document candidate and
namespace identities, discovery and scheduling, and the bounded algorithms. namespace identities, discovery and scheduling, and the bounded algorithms.

View File

@@ -32,11 +32,11 @@ structure as implemented when its changes land.
Constraints must reflect deliberately selected requirements and decisions. Constraints must reflect deliberately selected requirements and decisions.
Do not promote incidental implementation choices into architectural invariants. Do not promote incidental implementation choices into architectural invariants.
The collection-policy and CLI-ordering requirements below reflect accepted The implemented collection-policy and CLI-ordering constraints below reflect
[ADR 0017](../adr/0017-collection-sequence-policy.md) and accepted [ADR 0017](../adr/0017-collection-sequence-policy.md) and
[ADR 0018](../adr/0018-cli-after-structural-resolution.md). The [ADR 0018](../adr/0018-cli-after-structural-resolution.md). The configuration
[sequence roadmap](../roadmap/sequences.md) tracks the work to implement them; contract owns their current behavior; these architectural constraints describe
the configuration contract continues to describe implemented behavior. the system boundaries and guarantees that guide changes to that behavior.
## Success Criteria ## Success Criteria
@@ -373,8 +373,8 @@ as records survive, move, or are replaced. Identity diagnostics use paths and
available origin information without exposing identity values. The guarantee available origin information without exposing identity values. The guarantee
requires no new mutation-history system or exact reconstruction of causes for requires no new mutation-history system or exact reconstruction of causes for
records supplied by defaults or callbacks. Exact identity equality, declaration records supplied by defaults or callbacks. Exact identity equality, declaration
syntax, presence cases, and operation tables belong in the configuration contract syntax, presence cases, and operation tables belong in the
when implemented; the roadmap owns those details until then. [configuration contract](../config.md#strict-document-composition).
## Ownership And Confidentiality ## Ownership And Confidentiality

View File

@@ -6,112 +6,19 @@ commitments. Adopting a candidate requires an explicit design decision and a
separate plan. Significant architectural exclusions and their rationale belong separate plan. Significant architectural exclusions and their rationale belong
in ADRs; this document does not maintain a list of rejected proposals. in ADRs; this document does not maintain a list of rejected proposals.
## 1. Identified record sequences ## 1. Recursive body merging for identified records
Status: deferred. PromptKit proposed this capability from its retired proposal 2, Status: deferred. The implemented
**Namespaced Collections As Identified Records**. The original proposal is in the [collection policy](../config.md#strict-document-composition) uses `upsert` to
PromptKit repository at replace a complete matched record. Recursive merging of fields inside matching
`b5866dd:docs/roadmap/configuration-collections-identified-records.md`. records remains a separate candidate and would revisit the whole-record update
PromptKit selected mounted mappings instead; this feature is not a dependency boundary selected by [ADR 0017](../adr/0017-collection-sequence-policy.md).
of that design or a request to restore multiple installed prompt versions.
A narrower [sequence placement and composition feature](../config.md#strict-document-composition) Consider this only in response to a concrete consumer need. A proposal would need
is implemented: consumers can place imported mappings as sequence items and to define conflicts for overlapping body fields, removal of omitted fields,
register a single literal string identity field for duplicate-rejecting strict presence and ordering, and how provenance, history, sensitivity, and resource
composition. Precedence still replaces sequences as whole values. This entry context follow partially retained records. Any change requires a new decision and
tracks broader identified-record behavior that remains deferred and is not part implementation plan; this entry does not alter current upsert behavior.
of that implemented contract.
The active [sequence roadmap](sequences.md) now selects a narrower design for
collection policy, compound scalar identities, final application-registered
identity validation, and inheritance within identified sequences. It owns those
selected behaviors and their remaining decisions. The original broader proposal
below remains background for further consideration, particularly recursive
combination of matching record bodies; it does not override the active roadmap.
### Motivation and proposed behavior
Allow applications to declare that selected sequences contain records identified
by explicit fields, while retaining sequence-shaped output for slice decoding
and effective YAML. This could make composite identities and independently
authored catalogs more convenient than encoding identity in nested mapping keys.
Current [composition](../config.md#strict-document-composition) appends distinct
records only at explicitly registered paths; other sequences remain atomic.
Selected [overlays](../config.md#selected-overlays) always treat sequences
atomically.
The proposed broader opt-in registration would extend the current reusable
application definition from one identity field to a composite identity made of
an ordered, nonempty set of distinct direct string-field names. For example,
records at `profiles` could be identified by `(namespace, id)`. Records
`(provider, brief)`
and `(application, brief)` would coexist, and a later layer could update the
provider record's temperature while retaining its backend and model.
The requested semantics, all still subject to design review, are:
- Match exact string tuples, preserving component boundaries and spelling,
including empty strings. Every contribution supplies its complete identity;
defaults, inheritance, filenames, and normalization do not supply it.
- Retain distinct identities. Matching records from strict peers recursively
compose disjoint body fields and conflict on overlapping non-mapping body
values, even equal values. Equal identity fields act as structural keys rather
than conflicts and retain their contributing source evidence.
- Higher layers recursively overlay matching bodies. A changed identity denotes
a different record, not a rename. Proposed ordering is first contribution in
precedence-assembly order; matching records keep position and new ones append.
- Reject malformed identities, non-mapping records, non-null non-sequence values
at registered paths, and duplicate tuples within one source sequence. Later
layers cannot repair malformed structural identity in an acquired contribution.
- Treat an empty registered sequence as contributing no records; whole-path null
retains ordinary conflict/replacement semantics. Unregistered sequences,
including nested message lists, retain existing atomic behavior.
- Support record inheritance within the same registered sequence using an
`extends` mapping containing the complete parent tuple. Resolve only final
active relationships after precedence, preserve the child's identity, overlay
its body on the parent's body, and consume the directive before decoding.
Preserve cancellation, missing-parent/cycle errors, and declaring resource
contexts. Existing string-based mapping-sibling inheritance stays unchanged.
Integrate ordinary and layered loads, imports, mounted paths, selected overlays,
and whole-sequence CLI overrides. Keep origins, presence, history, sensitivity,
and resource contexts attached to the correct record despite different source
and final indexes. Diagnostics must retain source locations without exposing
sensitive identity values. Final inspection may use snapshot-specific sequence
indexes; existing atomic sequence diffs need not become identity-aware.
Successful results would have valid, unique identities, including after defaults
and application resolution, without a second merge or inheritance pass. Existing
source-version checks remain independent; consumed headers cannot supply missing
record identities. No identity-selector path syntax, arbitrary merge callbacks,
wildcard registration, per-record deletion/rename operator, multiple inheritance,
or cross-path parent references are requested.
### Questions to resolve before implementation
- **Need and delivery scope:** does an active consumer benefit enough to justify
the added semantics over keyed mappings? Are composite identities required?
Staging composition before inheritance is possible but would leave part of
the request incomplete.
- **Defaults and callbacks:** do default records merge by identity or retain
existing sequence-replacement behavior? How are callback-created duplicates,
identity edits, and reordering validated and reflected in provenance?
- **Null, empty, and order:** what happens when null clears a collection and a
later layer reintroduces records? How do absent and explicitly empty sequences
interact with defaults and first-contribution order?
- **Inheritance references:** how do peers compose relationship declarations,
and how are complete references enforced without assembling partial tuples
accidentally? What happens if identity fields overlap structural controls?
- **Registration paths:** how do overlapping registrations and paths beneath
sequence indexes behave when assembly changes those indexes?
- **Evidence and lifecycle:** how are record identities mapped between source
trees, history, inheritance, callback snapshots, and final indexes without
mixing records' provenance or sensitivity? Where do identity checks run relative
to header consumption and other structural processing?
Keep the feature deferred until its consumer value and full lifecycle design
justify reconsidering the sequence-merging exclusion. A correct final sequence
alone would not establish correct inspection or disclosure behavior.
## 2. Required version declarations for selected sources ## 2. Required version declarations for selected sources

View File

@@ -1,6 +1,6 @@
# Sequence Identity And Combination Implementation Plan # Sequence Identity And Combination Implementation Plan
Status: implementation in progress; Stages 1–28 complete. Status: implementation in progress; Stages 1–29 complete.
Audience: a Luna coding agent implementing one numbered stage per prompt, in Audience: a Luna coding agent implementing one numbered stage per prompt, in
order. This plan starts at commit order. This plan starts at commit
@@ -993,6 +993,15 @@ Validation: local documentation-link checks and whitespace review; run relevant
example tests if executable examples changed. Reuse Stage 28's successful example tests if executable examples changed. Reuse Stage 28's successful
code/race validation when its covered content is unchanged. code/race validation when its covered content is unchanged.
**Completion:** Reconciled the configuration contract for identity equality,
selectors, declarations, operation selection and presence, ownership,
inheritance, final registered-identity validation, and post-decode CLI ordering.
Updated consumer, root, internal, development, and architecture guidance; removed
implemented behavior from the deferred feature list while retaining recursive
body merging as future work. Updated ADR implementation references and preserved
intentional historical references. Verified maintained prose/example searches,
`go test . -run '^TestLocalDocumentationLinks$' -count=1`, and `git diff --check`.
## Stage 30 — Audit Scaling And Verify The Completed Target ## Stage 30 — Audit Scaling And Verify The Completed Target
Scope: a bounded implementation review and final validation, not another broad Scope: a bounded implementation review and final validation, not another broad

View File

@@ -28,9 +28,8 @@ sequences, selected overlays, and sibling inheritance. Typed defaults, CLI
assignments, and application resolution retain their own combination semantics; assignments, and application resolution retain their own combination semantics;
CLI application moves later in the loading lifecycle. CLI application moves later in the loading lifecycle.
This scope is narrower than the deferred Automatic recursive merging of matching records remains deferred
[identified-record sequences proposal](future.md#1-identified-record-sequences). (see [future work](future.md#1-recursive-body-merging-for-identified-records));
Automatic recursive merging of matching records remains outside this scope;
explicit inheritance between distinct records is included. The initial explicit inheritance between distinct records is included. The initial
declaration surface is `configkit.sequences`; `key` and `mode` shorthand on declaration surface is `configkit.sequences`; `key` and `mode` shorthand on
imports is deferred. Application lists remain imports is deferred. Application lists remain