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
its safe changed-region records and maintained workflows.
Sources can also be explicitly placed as sequence items, and definitions can
register selected sequences to append records with distinct string IDs during
strict composition. Higher-priority sequences still replace lower-priority
sequences as whole values. See the [sequence contract](docs/config.md#strict-document-composition),
[maintained prompt example](docs/consumers/README.md#identified-prompt-sequences),
and [ADR 0014](docs/adr/0014-sequence-placement-and-composition.md).
Sources can also be explicitly placed as sequence items. Configuration
declarations and application registrations can give selected sequences scalar
identities and choose how they combine across precedence and inheritance.
Strict peers combine distinct records, while higher-priority collections can
replace, append, or upsert whole records. See the
[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,
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
imports form one strictly composed tier. Explicit underlay groups sit below it
and above typed defaults; a selected overlay applies before inheritance, while
explicit CLI overrides apply to the decoded configuration before application
resolution. The [configuration contract](docs/config.md#strict-document-composition)
owns the detailed combination rules and input-specific constraints. At
definition-registered paths only, strict composition can append records with
distinct explicit IDs; ordinary and unregistered sequences keep their conflict
or whole-value replacement behavior.
explicit CLI overrides apply after decoding and before application resolution.
The [configuration contract](docs/config.md#strict-document-composition) owns
the detailed combination rules and input-specific constraints. Declared or
registered collections combine distinct identified records within strict tiers
and use their selected operation at precedence boundaries; other sequences keep
their strict-conflict and whole-value-replacement behavior.
The [architecture goals](docs/policy/architecture.md#success-criteria) explain
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,
and sensitivity information as mapping-sibling inheritance.
The configuration contract will define declaration syntax, identity comparison,
omission and empty-value behavior, and diagnostics when the feature is
implemented.
The [configuration contract](../config.md#strict-document-composition) defines
declaration syntax, identity comparison, omission and empty-value behavior, and
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
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
and application resolution. The configuration contract and consumer guidance
must explain these behavior changes when they are implemented.
and application resolution. The [configuration contract](../config.md#explicit-cli-overrides)
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` |
Every non-mapping overlap is a conflict, even when values are equal, except for
sequence/sequence contributions at a registered sequence identity destination
or a source-declared collection destination. Nulls remain atomic conflicts.
Unregistered and undeclared sequences conflict when repeated and are never joined
sequence/sequence contributions at a destination with effective identity from an
application registration, a current YAML `key` declaration, or retained lower
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
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
remain literal mapping keys; explicit index segments and reserved `configkit` or
mapping-valued `extends` segments are invalid. The root selector is harmless under
the mapping-root schema. Each registration requires one or more literal field
names; compound field sets are normalized as sets, and field names are not
otherwise normalized.
the mapping-root schema. Selector segments consume one mapping level and match a
complete destination; an any-mapping-key segment matches exactly one key, not an
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
string, number, boolean, or explicit null. The type-tagged tuple preserves
category distinctions, while equivalent finite decimal spellings such as `1`,
`1.0`, and `1e0` compare as the same number. 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
At each selected path, records must provide every effective identity field as a
scalar string, number, boolean, or explicit null. Field names form a set, so
order and repetition do not affect compound identity. The type-tagged tuple
preserves category distinctions: strings compare exactly, including empty
strings; numbers, booleans, and null remain distinct categories. Finite numbers
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
duplicate without exposing identity values. Missing paths and non-sequence values
do not fail by themselves. Equivalent overlapping registrations coalesce;
incompatible overlaps and invalid registrations produce `options.invalid` before
do not fail by themselves. Equivalent overlapping registrations coalesce.
Incompatible overlaps and invalid registrations produce `options.invalid` before
source acquisition. Unused and root registrations are allowed and have no effect.
Registration controls strict composition and supplies identity fields for parent
lookup when surviving records in that sequence use `extends`. Dynamic selectors
apply at strict-composition and inheritance destinations without requiring the
application to enumerate mapping keys. Each underlay group and the main tier has
independent duplicate-identity state. Precedence assembly is unchanged: a present
higher-priority sequence replaces the lower sequence as one value, including at a
registered path.
Registrations provide identity for strict composition, sequence operations,
inheritance lookup, and final validation. Dynamic selectors apply at concrete
strict-composition, inheritance, and final-result destinations without requiring
the application to enumerate mapping keys. Each strict tier has independent
duplicate-identity state among its peers; layered precedence and inheritance
then apply the collection operation described below.
After effective secret lookup, the shared load lifecycle validates every matching
sequence in the final typed projection before application semantic validation.
This catches identities introduced by typed defaults, CLI assignment, or recorded
resolution, in both ordinary and layered loads. Only actual sequences are checked;
absent paths and other shapes remain the schema or application validator's concern.
Identity fields are read from effective typed payload regardless of authored
presence. Diagnostics use concrete collection and item paths and available source
locations, and never include identity or credential values. The guarantee ends at
successful publication; later caller mutations are outside it. The accepted
rationale is recorded in
[ADR 0014](adr/0014-sequence-placement-and-composition.md).
The [maintained prompt catalog](consumers/README.md#identified-prompt-sequences)
shows item path and glob imports, helper-supplied identity, and main-tier
replacement of a lower-priority sequence.
Final registration checks run in both ordinary and layered loads after effective
secret lookup and before application semantic validation. They examine actual
final typed sequences, including values introduced by defaults, CLI, or recorded
resolution; they do not require path existence or sequence shape. Diagnostics
use concrete collection and item paths and available source locations, without
exposing identity or credential values. The guarantee ends when loading publishes
successfully and does not cover later caller mutations.
YAML-only identity is enforced during structural composition, precedence, and
identified inheritance; it carries no final-result guarantee after typed
defaults, CLI, or application resolution. Applications that need that guarantee
register the identity constraint.
The [maintained catalog examples](consumers/README.md#identified-prompt-sequences)
show strict peers, precedence operations, inheritance, dynamic destinations, and
the distinction between YAML-only declarations and application registrations.
When an enabled source-version mode is selected, declarations are checked in each
source's own coordinates before placement and composition. Accepted non-main
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.
Ordinary sources, layered inputs, and selected overlays may declare collection
behavior under `configkit.sequences` at the document root. Each entry has a required literal
`destination` and may specify `key` as one string or a nonempty list of strings,
plus a `mode` of `replace`, `append`, or `upsert`. These controls are removed
before application decoding. A declaration destination is relative to that
source's placement, so a mounted fragment's declaration is mounted with its
values. Declarations from
strict peers must agree on identity fields and on any explicitly supplied mode;
they apply even when the declaring source has no value at that destination.
Singleton sequence contributions are validated as well as peers. A key supplies
the identity used by `append` and `upsert`; without an explicit or retained mode,
a keyed collection uses `upsert`, while an unkeyed collection uses `replace`.
`append` keeps contribution order and rejects repeated identities. `upsert`
replaces a complete matched record at its existing position and appends new
identities in incoming order; it does not merge record fields.
behavior under `configkit.sequences` at the document root. Each entry has a
required literal `destination` and may specify `key` as one string or a nonempty
list of strings, plus a `mode` of `replace`, `append`, or `upsert`. These
controls are removed before application decoding. A declaration destination is
relative to that source's placement, so a mounted fragment's declaration is
mounted with its values. Declarations from strict peers must agree on identity
fields and on any explicitly supplied mode; omission expresses no mode
preference. They apply even when the declaring source has no value at that
destination: a key validates an existing retained sequence or remains pending
until records arrive, while a mode-only declaration affects later combinations
without recombining earlier tiers. A key supplies the identity used by `append`
and `upsert` and is checked against any application registration.
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
imports disabled, and each strict scope in layered loading. Layered groups and
main apply their resolved sequence operation between precedence tiers; a higher
strict scope inherits the lower identity and explicit mode before peer
composition. Overlay declarations apply after the base source graph is composed
and must agree with retained collection identity and any application
registration. During mapping-sibling inheritance, a parent's YAML identity can
follow its collection to the child destination, while the parent's explicit
operation stays at the parent destination. A child declaration selects the
operation at its destination; absent one, keyed collections use upsert and
unkeyed collections use replace. These policies do not change CLI behavior. A root
`configkit.imports` declaration still requires `Options.Imports`; `NoSource` has
no declaration scope.
imports disabled, and each strict scope in layered loading. Before composing a
higher tier's peers, ConfigKit makes applicable lower identity and explicit mode
available; after peer composition, the tier applies its resolved operation
against the lower collection. Selected overlays use the same collection policy
after the base source graph is composed. During mapping-sibling inheritance, a
parent's YAML identity can follow its collection to the child destination, while
the parent's explicit operation stays at the parent destination. The child
destination selects its operation; absent one, effective identity implies
upsert and its absence implies replace. Whole-sequence replacement discards
lower YAML identity and uses the replacing scope's key declaration, if any;
without one, the collection is unkeyed unless an application registration still
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 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
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
paths in namespace-path lexical order, preserving source-record and version-callback
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
schedule. Item positions and diagnostic paths follow the resulting assembly order.
Each underlay group likewise acquires its inputs before dependency-ready assembly
in one strict scope. Independent groups remain separate precedence tiers; a higher
tier still replaces a lower tier's sequence values wholesale. Assembly order never
permits replacement.
in one strict scope. Independent groups remain separate precedence tiers; at a
declared or registered destination, the assembled higher sequence uses the
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
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
placement requires a nonempty effective destination and wraps the imported
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
registered through `Definition.SequenceIdentities`; registration does not
change placement or precedence behavior. Sequence records retain source
locations through placement and history; indexes describe their assembled
positions while source coordinates continue to identify the declaring files.
Header/version policy and final application validation retain their existing
owners and timing; sequence registration is a strict-composition rule only.
or infer identity fields. Repeated sequences combine only when the destination
has an applicable YAML identity declaration or application registration; source
placement remains independent of collection identity and operation. Sequence
records retain source locations through placement and history; indexes describe
their assembled positions while source coordinates continue to identify the
declaring files.
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
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 |
| 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 |
| 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
executable examples and ordinary tests. It contains no private application data,
@@ -184,43 +184,35 @@ import, source-location, and ownership behavior.
## Identified prompt sequences
[`LoadPromptCatalog`](../../examples/consumers/prompt_catalog.go) uses one
definition registration for the literal `prompts` path and `id` field. Its
load-wide filename defaults accept two patterns, an explicit directory
declaration overrides those patterns, and an exclusion omits one matching
candidate. A nested ordinary helper import supplies an item's ID. A separate
empty optional directory search is read from `SourceInfo.ImportSelections`.
The executable example prints both the scheduled prompt order and the single
empty-search outcome; the behavior test also follows a mounted resource through
its effective metadata origin to the declaring source context. The completed
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.
[`LoadPromptCatalog`](../../examples/consumers/prompt_catalog.go) shows the
smaller import-focused adoption path: a registered `prompts.id` identity,
directory and glob selection, a helper import that supplies an item's ID, and
resource lookup through the effective source context. Its executable examples
and tests are in
[`prompt_catalog_test.go`](../../examples/consumers/prompt_catalog_test.go), with
complete [catalog](../../examples/consumers/testdata/prompt-catalog/config.yml)
and [required-file](../../examples/consumers/testdata/prompt-catalog/simple.yml)
fixtures.
[`LoadRequiredPromptCatalog`](../../examples/consumers/prompt_catalog.go) and
[`Example_requiredPromptCatalog`](../../examples/consumers/prompt_catalog_test.go)
keep the smaller adoption path visible: one explicitly required file import,
the same identity registration, and the same application validation.
[`LoadSequenceCatalog`](../../examples/consumers/sequence_catalog.go) integrates
an underlay declaration, imported main fragments, identified-record inheritance,
selected overlay `append`, `upsert`, and `replace`, a typed CLI override, and
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
`extends: {id: "base-id"}`. ConfigKit resolves these references within the
completed prompt sequence after tier assembly, preserves the child's own ID, and
records inherited values at the child's paths. The
[configuration contract](../config.md#sibling-inheritance) defines the exact
reference and nested collection behavior.
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.
The examples keep prompt meaning and domain checks in the consuming application.
The [configuration contract](../config.md#strict-document-composition) owns
declaration, identity, operation, ownership, and final-validation semantics;
[sibling inheritance](../config.md#sibling-inheritance) defines record
relationships, and the [CLI contract](../config.md#explicit-cli-overrides) owns
override ordering.
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

View File

@@ -135,12 +135,13 @@ Current behavior belongs to the configuration contract's
[input destinations](config.md#input-destinations),
[imports](config.md#explicit-imports), and
[shared source-version checks](config.md#shared-source-version-checks) sections.
Explicit sequence-item placement and registered strict composition are owned by
the [strict composition](config.md#strict-document-composition) and
[imports](config.md#explicit-imports) sections. The
[maintained prompt catalog](consumers/README.md#identified-prompt-sequences)
shows the current consumer boundary, and [ADR 0014](adr/0014-sequence-placement-and-composition.md)
records the decision.
Explicit sequence-item placement, collection operations, identity registration,
and final registered-identity validation are owned by the
[strict composition](config.md#strict-document-composition) section;
[imports](config.md#explicit-imports) owns acquisition and scheduling. The
[maintained sequence catalog](consumers/README.md#identified-prompt-sequences)
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
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` |
| 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'` |
| 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'` |
| 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` |

View File

@@ -65,11 +65,18 @@ returns a closed cycle rotated to its smallest key; blocked dependents are not
reported as cycle members.
Import composition schedules a main tier or one underlay group as a single
strict-scope graph. 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.
strict-scope graph. Applicable collection declarations are gathered for the
scope before peer composition, including identity inherited from lower tiers.
Identified peer sequences then combine distinct records in assembled source and
list order; after the strict scope completes, layered assembly applies the
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),
[`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,
grouped strict composition, recursive precedence assembly, per-input mapping
and sequence-item placement, definition-registered distinct-ID sequence
composition within strict tiers, and immediate-parent-relative import
placement within that assembly. Higher-priority sequences replace lower
sequences as whole values. The engine also owns dependency-ready,
destination-local sibling inheritance before typed decoding, plus shared
source-version checking with sanitized declaration evidence.
and sequence-item placement, YAML collection declarations and operations for
identified sequences, and application identity registrations for strict
composition, inheritance, and final validation. It applies the selected
collection operation at precedence boundaries and owns dependency-ready,
destination-local inheritance before typed decoding. CLI assignment follows
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
globs; load-wide defaults and source-local empty-selection evidence cross the
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
[effective configuration diffs](../config.md#effective-configuration-diffs).
The [strict composition contract](../config.md#strict-document-composition)
owns sequence placement, registration, replacement, and history behavior; the
[consumer guide](../consumers/README.md#identified-prompt-sequences) shows the
maintained example.
owns sequence declarations, identity, operations, ownership, and final
validation; [CLI overrides](../config.md#explicit-cli-overrides) own override
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 [architecture policy](../policy/architecture.md) owns contributor
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)
records the shared dependency-ready ordering decision; [ADR
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.

View File

@@ -32,11 +32,11 @@ structure as implemented when its changes land.
Constraints must reflect deliberately selected requirements and decisions.
Do not promote incidental implementation choices into architectural invariants.
The collection-policy and CLI-ordering requirements below reflect accepted
[ADR 0017](../adr/0017-collection-sequence-policy.md) and
[ADR 0018](../adr/0018-cli-after-structural-resolution.md). The
[sequence roadmap](../roadmap/sequences.md) tracks the work to implement them;
the configuration contract continues to describe implemented behavior.
The implemented collection-policy and CLI-ordering constraints below reflect
accepted [ADR 0017](../adr/0017-collection-sequence-policy.md) and
[ADR 0018](../adr/0018-cli-after-structural-resolution.md). The configuration
contract owns their current behavior; these architectural constraints describe
the system boundaries and guarantees that guide changes to that behavior.
## 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
requires no new mutation-history system or exact reconstruction of causes for
records supplied by defaults or callbacks. Exact identity equality, declaration
syntax, presence cases, and operation tables belong in the configuration contract
when implemented; the roadmap owns those details until then.
syntax, presence cases, and operation tables belong in the
[configuration contract](../config.md#strict-document-composition).
## 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
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,
**Namespaced Collections As Identified Records**. The original proposal is in the
PromptKit repository at
`b5866dd:docs/roadmap/configuration-collections-identified-records.md`.
PromptKit selected mounted mappings instead; this feature is not a dependency
of that design or a request to restore multiple installed prompt versions.
Status: deferred. The implemented
[collection policy](../config.md#strict-document-composition) uses `upsert` to
replace a complete matched record. Recursive merging of fields inside matching
records remains a separate candidate and would revisit the whole-record update
boundary selected by [ADR 0017](../adr/0017-collection-sequence-policy.md).
A narrower [sequence placement and composition feature](../config.md#strict-document-composition)
is implemented: consumers can place imported mappings as sequence items and
register a single literal string identity field for duplicate-rejecting strict
composition. Precedence still replaces sequences as whole values. This entry
tracks broader identified-record behavior that remains deferred and is not part
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.
Consider this only in response to a concrete consumer need. A proposal would need
to define conflicts for overlapping body fields, removal of omitted fields,
presence and ordering, and how provenance, history, sensitivity, and resource
context follow partially retained records. Any change requires a new decision and
implementation plan; this entry does not alter current upsert behavior.
## 2. Required version declarations for selected sources

View File

@@ -1,6 +1,6 @@
# 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
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
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
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;
CLI application moves later in the loading lifecycle.
This scope is narrower than the deferred
[identified-record sequences proposal](future.md#1-identified-record-sequences).
Automatic recursive merging of matching records remains outside this scope;
Automatic recursive merging of matching records remains deferred
(see [future work](future.md#1-recursive-body-merging-for-identified-records));
explicit inheritance between distinct records is included. The initial
declaration surface is `configkit.sequences`; `key` and `mode` shorthand on
imports is deferred. Application lists remain