Document sequence composition for consumers
This commit is contained in:
18
README.md
18
README.md
@@ -26,6 +26,13 @@ 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
|
||||||
|
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).
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Enabled bool `yaml:"enabled"`
|
Enabled bool `yaml:"enabled"`
|
||||||
@@ -62,7 +69,10 @@ 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 and explicit CLI overrides sit
|
and above typed defaults; a selected overlay and explicit CLI overrides sit
|
||||||
above it. The [configuration contract](docs/config.md#strict-document-composition)
|
above it. The [configuration contract](docs/config.md#strict-document-composition)
|
||||||
owns the detailed combination rules and input-specific constraints.
|
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.
|
||||||
|
|
||||||
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
|
||||||
@@ -72,8 +82,10 @@ consideration in future releases.
|
|||||||
The [configuration contract](docs/config.md) describes implemented behavior,
|
The [configuration contract](docs/config.md) describes implemented behavior,
|
||||||
including [input destinations](docs/config.md#input-destinations). The
|
including [input destinations](docs/config.md#input-destinations). The
|
||||||
[consumer adoption guide](docs/consumers/README.md) provides maintained simple,
|
[consumer adoption guide](docs/consumers/README.md) provides maintained simple,
|
||||||
layered, and mounted-collection examples alongside the migration shapes. The
|
layered, mounted-collection, and identified-prompt examples alongside the
|
||||||
accepted placement decision is recorded in [ADR 0011](docs/adr/0011-input-destinations.md).
|
migration shapes. Input placement decisions are recorded in
|
||||||
|
[ADR 0011](docs/adr/0011-input-destinations.md) and sequence placement and
|
||||||
|
composition in [ADR 0014](docs/adr/0014-sequence-placement-and-composition.md).
|
||||||
See the [development guide](docs/development.md) for repository orientation and
|
See the [development guide](docs/development.md) for repository orientation and
|
||||||
the [release procedure](docs/release.md) for maintainer-only candidate and
|
the [release procedure](docs/release.md) for maintainer-only candidate and
|
||||||
publication steps.
|
publication steps.
|
||||||
|
|||||||
@@ -2,8 +2,10 @@
|
|||||||
|
|
||||||
## Status
|
## Status
|
||||||
|
|
||||||
Accepted. Implementation status and sequencing are tracked in the
|
Accepted and implemented. The [configuration contract](../config.md#strict-document-composition)
|
||||||
[sequence composition implementation plan](../roadmap/implementation.md).
|
defines current behavior, and the [consumer guide](../consumers/README.md#identified-prompt-sequences)
|
||||||
|
shows the maintained example. Implementation status and delivery sequencing
|
||||||
|
are tracked in the [implementation plan](../roadmap/implementation.md).
|
||||||
|
|
||||||
## Date
|
## Date
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,11 @@ have index zero. Explicit empty groups and `NoSource` consume no source ID.
|
|||||||
Byte, source, node, and glob-entry budgets are shared across the load, while
|
Byte, source, node, and glob-entry budgets are shared across the load, while
|
||||||
the existing per-source and import-depth bounds still apply.
|
the existing per-source and import-depth bounds still apply.
|
||||||
|
|
||||||
|
When a source mapping is explicitly placed as an item, its effective destination
|
||||||
|
is the sequence container. After assembly assigns an index, nested source
|
||||||
|
destinations are projected through that item. Physical source locations and
|
||||||
|
resource contexts continue to identify the declaring source.
|
||||||
|
|
||||||
#### Input destinations
|
#### Input destinations
|
||||||
|
|
||||||
`Input.Destination` places the source's application mapping beneath a path
|
`Input.Destination` places the source's application mapping beneath a path
|
||||||
@@ -411,6 +416,11 @@ the descendant can therefore retain history after `Lookup` stops reporting it as
|
|||||||
effective. Equal-valued input is still an explicit base definition, while a derived
|
effective. Equal-valued input is still an explicit base definition, while a derived
|
||||||
value for absent input remains non-explicit.
|
value for absent input remains non-explicit.
|
||||||
|
|
||||||
|
Appending registered records during strict composition assigns each contribution
|
||||||
|
its assembled sequence index in history. A later precedence tier that supplies a
|
||||||
|
sequence records replacement at the sequence path; history does not imply
|
||||||
|
identity-based merging across tiers.
|
||||||
|
|
||||||
A mapping assembled from the selected file and imports has one composite base origin
|
A mapping assembled from the selected file and imports has one composite base origin
|
||||||
whose locations retain source traversal order. A mapping also visited by an overlay
|
whose locations retain source traversal order. A mapping also visited by an overlay
|
||||||
has an overlay-layer composite origin with the lower contributing locations followed
|
has an overlay-layer composite origin with the lower contributing locations followed
|
||||||
@@ -790,6 +800,14 @@ a present higher-priority sequence replaces the lower sequence as one value,
|
|||||||
including at a registered path. Overlays, CLI overrides, defaults, inheritance,
|
including at a registered path. Overlays, CLI overrides, defaults, inheritance,
|
||||||
and application resolution do not run the registered identity check. The accepted
|
and application resolution do not run the registered identity check. The accepted
|
||||||
rationale is recorded in [ADR 0014](adr/0014-sequence-placement-and-composition.md).
|
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.
|
||||||
|
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
|
||||||
|
record identity. Final typed decoding and application validation still run on the
|
||||||
|
completed configuration.
|
||||||
|
|
||||||
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.
|
||||||
@@ -932,7 +950,11 @@ 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 still conflict unless their path is
|
||||||
registered through `Definition.SequenceCompositions`; registration does not
|
registered through `Definition.SequenceCompositions`; registration does not
|
||||||
change placement or precedence behavior.
|
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.
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -21,6 +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, and main-tier replacement of a lower-priority collection | Prompt 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,
|
||||||
@@ -163,6 +164,24 @@ relative resources, and strict peer conflicts. The
|
|||||||
[configuration contract](../config.md#input-destinations) owns shared placement,
|
[configuration contract](../config.md#input-destinations) owns shared placement,
|
||||||
import, source-location, and ownership behavior.
|
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 main
|
||||||
|
file imports one prompt by path and others by glob, placing each source as an
|
||||||
|
item. A nested ordinary helper import supplies an item's ID. The main tier
|
||||||
|
strictly appends the distinct records in contribution order; its completed
|
||||||
|
sequence replaces the lower-priority default collection as one value.
|
||||||
|
|
||||||
|
The example's `validatePromptCatalog` remains application-owned. It checks that
|
||||||
|
prompt names and message lists satisfy this consumer's requirements after
|
||||||
|
ConfigKit has composed, projected, and decoded the configuration. It does not
|
||||||
|
add recursive record merging, identity-based overlay, or final uniqueness checks
|
||||||
|
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
|
||||||
fields are known; validation selects which fields apply to each module. Runtime-
|
fields are known; validation selects which fields apply to each module. Runtime-
|
||||||
|
|||||||
@@ -131,6 +131,12 @@ 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
|
||||||
|
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.
|
||||||
Potential enhancements are tracked in [future features](roadmap/future.md).
|
Potential enhancements are tracked in [future features](roadmap/future.md).
|
||||||
|
|
||||||
Install the Go version required by `go.mod` or a compatible newer toolchain.
|
Install the Go version required by `go.mod` or a compatible newer toolchain.
|
||||||
|
|||||||
@@ -9,9 +9,12 @@ 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
|
||||||
placement and immediate-parent-relative import placement within that
|
and sequence-item placement, definition-registered distinct-ID sequence
|
||||||
assembly, destination-local sibling inheritance before typed decoding, and
|
composition within strict tiers, and immediate-parent-relative import
|
||||||
shared source-version checking with sanitized declaration evidence.
|
placement within that assembly. Higher-priority sequences replace lower
|
||||||
|
sequences as whole values. The engine also owns destination-local sibling
|
||||||
|
inheritance before typed decoding, plus shared source-version checking with
|
||||||
|
sanitized declaration evidence.
|
||||||
It retains each source's effective placement alongside physical source
|
It retains each source's effective placement alongside physical source
|
||||||
identity and owns schema
|
identity and owns schema
|
||||||
inspection, lifecycle coordination, callback auditing,
|
inspection, lifecycle coordination, callback auditing,
|
||||||
@@ -48,6 +51,10 @@ The [configuration contract](../config.md) owns implemented YAML and lifecycle
|
|||||||
semantics, including [input destinations](../config.md#input-destinations),
|
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)
|
||||||
|
owns sequence placement, registration, replacement, and history behavior; the
|
||||||
|
[consumer guide](../consumers/README.md#identified-prompt-sequences) shows the
|
||||||
|
maintained example.
|
||||||
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
|
||||||
@@ -59,3 +66,5 @@ and [release procedure](../release.md) for source-candidate gates. [ADR
|
|||||||
post-assembly structural operation. [ADR 0012](../adr/0012-relative-import-destinations.md)
|
post-assembly structural operation. [ADR 0012](../adr/0012-relative-import-destinations.md)
|
||||||
records the relative-import extension; [ADR 0013](../adr/0013-shared-source-version-checks.md)
|
records the relative-import extension; [ADR 0013](../adr/0013-shared-source-version-checks.md)
|
||||||
records the source-version decision.
|
records the source-version decision.
|
||||||
|
[ADR 0014](../adr/0014-sequence-placement-and-composition.md) records explicit
|
||||||
|
sequence placement and composition.
|
||||||
|
|||||||
@@ -163,19 +163,22 @@ framework on this library.
|
|||||||
|
|
||||||
Within a configuration tier, independent contributions use strict composition:
|
Within a configuration tier, independent contributions use strict composition:
|
||||||
shared mappings combine recursively, while overlapping non-mapping definitions
|
shared mappings combine recursively, while overlapping non-mapping definitions
|
||||||
are conflicts, including equal values. Between precedence tiers, intentional
|
are conflicts, including equal values, except that sequences at explicitly
|
||||||
overlay combines mappings recursively, retains omitted lower-priority children,
|
registered paths append records with distinct present string identities. Between
|
||||||
|
precedence tiers, intentional overlay combines mappings recursively, retains
|
||||||
|
omitted lower-priority children,
|
||||||
and replaces other present values according to the existing overlay rules.
|
and replaces other present values according to the existing overlay rules.
|
||||||
Tier precedence is explicit; traversal order within a tier establishes stable
|
Tier precedence is explicit; traversal order within a tier establishes stable
|
||||||
reporting, not permission to override. The distinction and its rationale are
|
reporting, not permission to override. The distinction and its rationale are
|
||||||
recorded in [ADR 0001](../adr/0001-separate-composition-and-overlay.md).
|
recorded in [ADR 0001](../adr/0001-separate-composition-and-overlay.md).
|
||||||
|
|
||||||
At definition-registered sequence paths, strict composition appends mapping
|
Sequence-item placement and sequence registration are explicit source and
|
||||||
records with distinct present string identities and rejects duplicates.
|
definition controls; registration does not change precedence replacement. The
|
||||||
Placement and registration are explicit source and definition controls; they do
|
[configuration contract](../config.md#strict-document-composition) defines the
|
||||||
not change precedence replacement. The [configuration contract](../config.md#strict-document-composition)
|
behavior, [ADR 0014](../adr/0014-sequence-placement-and-composition.md) records
|
||||||
defines the behavior, and [ADR 0014](../adr/0014-sequence-placement-and-composition.md)
|
the decision, and the [consumer guide](../consumers/README.md#identified-prompt-sequences)
|
||||||
records the decision.
|
shows the implemented subset. This feature does not authorize arbitrary
|
||||||
|
configurable merge strategies.
|
||||||
|
|
||||||
The main document and its imports form a strictly composed tier. Explicit
|
The main document and its imports form a strictly composed tier. Explicit
|
||||||
underlay groups compose strictly within each group, then combine recursively
|
underlay groups compose strictly within each group, then combine recursively
|
||||||
|
|||||||
@@ -15,11 +15,12 @@ PromptKit repository at
|
|||||||
PromptKit selected mounted mappings instead; this feature is not a dependency
|
PromptKit selected mounted mappings instead; this feature is not a dependency
|
||||||
of that design or a request to restore multiple installed prompt versions.
|
of that design or a request to restore multiple installed prompt versions.
|
||||||
|
|
||||||
A narrower [sequence placement and composition roadmap](sequence-composition.md)
|
A narrower [sequence placement and composition feature](../config.md#strict-document-composition)
|
||||||
now covers placing source mappings as sequence items, single-field identities,
|
is implemented: consumers can place imported mappings as sequence items and
|
||||||
duplicate rejection during strict composition, and whole-sequence replacement
|
register a single literal string identity field for duplicate-rejecting strict
|
||||||
between precedence layers. The additional capabilities below remain deferred
|
composition. Precedence still replaces sequences as whole values. This entry
|
||||||
and are not requirements of that roadmap.
|
tracks broader identified-record behavior that remains deferred and is not part
|
||||||
|
of that implemented contract.
|
||||||
|
|
||||||
### Motivation and proposed behavior
|
### Motivation and proposed behavior
|
||||||
|
|
||||||
@@ -27,13 +28,16 @@ Allow applications to declare that selected sequences contain records identified
|
|||||||
by explicit fields, while retaining sequence-shaped output for slice decoding
|
by explicit fields, while retaining sequence-shaped output for slice decoding
|
||||||
and effective YAML. This could make composite identities and independently
|
and effective YAML. This could make composite identities and independently
|
||||||
authored catalogs more convenient than encoding identity in nested mapping keys.
|
authored catalogs more convenient than encoding identity in nested mapping keys.
|
||||||
Current [composition](../config.md#strict-document-composition) and
|
Current [composition](../config.md#strict-document-composition) appends distinct
|
||||||
[overlay](../config.md#selected-overlays) treat sequences atomically.
|
records only at explicitly registered paths; other sequences remain atomic.
|
||||||
|
Selected [overlays](../config.md#selected-overlays) always treat sequences
|
||||||
|
atomically.
|
||||||
|
|
||||||
The proposed opt-in registration belongs in the reusable application definition:
|
The proposed broader opt-in registration would extend the current reusable
|
||||||
an exact effective sequence path after input/import placement, plus an ordered,
|
application definition from one identity field to a composite identity made of
|
||||||
nonempty set of distinct direct string-field names. For example, records at
|
an ordered, nonempty set of distinct direct string-field names. For example,
|
||||||
`profiles` could be identified by `(namespace, id)`. Records `(provider, brief)`
|
records at `profiles` could be identified by `(namespace, id)`. Records
|
||||||
|
`(provider, brief)`
|
||||||
and `(application, brief)` would coexist, and a later layer could update the
|
and `(application, brief)` would coexist, and a later layer could update the
|
||||||
provider record's temperature while retaining its backend and model.
|
provider record's temperature while retaining its backend and model.
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Implementation Plan: Sequence Placement and Composition
|
# Implementation Plan: Sequence Placement and Composition
|
||||||
|
|
||||||
Status: implementation in progress; stages 1–12 completed.
|
Status: implementation in progress; stages 1–13 completed.
|
||||||
|
|
||||||
## Purpose and authority
|
## Purpose and authority
|
||||||
|
|
||||||
@@ -756,6 +756,24 @@ Validation: executable example/consumer tests, local documentation-link tests,
|
|||||||
whitespace review, and `./scripts/check.sh`.
|
whitespace review, and `./scripts/check.sh`.
|
||||||
Completion: current docs and tested public examples describe what actually lands.
|
Completion: current docs and tested public examples describe what actually lands.
|
||||||
|
|
||||||
|
Completion evidence: the canonical configuration contract and architecture
|
||||||
|
policy now describe placement, registered strict composition, version/header
|
||||||
|
boundaries, source containers, history, and unchanged precedence. README,
|
||||||
|
consumer, development, and internal guides link to those contracts and the
|
||||||
|
maintained prompt-catalog example. The example uses disposable in-repository
|
||||||
|
fixtures to demonstrate path/glob item imports, a helper-supplied identity,
|
||||||
|
strict composition, whole-sequence replacement of defaults, and consumer-owned
|
||||||
|
validation. The feature roadmap and ADR status point to the implemented contract
|
||||||
|
and delivery record; broader composite-identity behavior remains deferred.
|
||||||
|
These checks passed with Go `go1.26.9 linux/amd64`:
|
||||||
|
|
||||||
|
- `GOTOOLCHAIN=local GOPROXY=off go test ./examples/consumers`
|
||||||
|
- `GOTOOLCHAIN=local GOPROXY=off go test -race ./...`
|
||||||
|
- `GOTOOLCHAIN=local GOPROXY=off ./scripts/check.sh`
|
||||||
|
- `git diff --check`
|
||||||
|
|
||||||
|
No environmental limitation affected validation; checks ran on Linux/amd64.
|
||||||
|
|
||||||
## Stage 14 — Review the completed unit and hand off
|
## Stage 14 — Review the completed unit and hand off
|
||||||
|
|
||||||
- Read the complete implementation diff against `2051177` and the feature
|
- Read the complete implementation diff against `2051177` and the feature
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
# Sequence-Item Placement and Identity-Based Composition
|
# Sequence-Item Placement and Identity-Based Composition
|
||||||
|
|
||||||
Status: design decisions settled; not implemented. This roadmap owns the target
|
Status: implemented. This roadmap records the target state and accepted behavior.
|
||||||
state and accepted behavior. The [implementation plan](implementation.md) owns
|
The [configuration contract](../config.md#strict-document-composition) defines
|
||||||
concrete API/syntax choices, execution order, validation, and progress.
|
the current behavior, and the [implementation plan](implementation.md) records
|
||||||
|
delivery sequencing and validation.
|
||||||
|
|
||||||
## Goal and current baseline
|
## Goal and current baseline
|
||||||
|
|
||||||
@@ -11,13 +12,12 @@ files. Placement makes a source mapping one sequence item; identity-based strict
|
|||||||
composition combines distinct items and rejects repeated identities. These are
|
composition combines distinct items and rejects repeated identities. These are
|
||||||
complementary operations, with explicit consumer opt-in.
|
complementary operations, with explicit consumer opt-in.
|
||||||
|
|
||||||
Current [input destinations](../config.md#input-destinations) place source
|
Sources can explicitly place mappings as sequence items at non-root destinations,
|
||||||
mappings beneath mapping-key paths. Imports support immediate-parent-relative
|
and definitions can register literal sequence paths with one literal string
|
||||||
destinations. Current [strict composition](../config.md#strict-document-composition)
|
identity field for duplicate-rejecting strict composition. Ordinary unregistered
|
||||||
combines mappings recursively and rejects other overlaps, while
|
sequences retain strict conflict behavior. [Precedence assembly](../config.md#layered-loading)
|
||||||
[precedence assembly](../config.md#layered-loading) and
|
and [selected overlays](../config.md#selected-overlays) continue to replace
|
||||||
[selected overlays](../config.md#selected-overlays) replace sequences wholesale.
|
sequences wholesale. The canonical contract documents the exact rules and limits.
|
||||||
Neither sequence-item placement nor sequence-composition registration exists today.
|
|
||||||
|
|
||||||
This roadmap covers a narrower feature than the
|
This roadmap covers a narrower feature than the
|
||||||
[identified record sequences candidate](future.md#1-identified-record-sequences).
|
[identified record sequences candidate](future.md#1-identified-record-sequences).
|
||||||
|
|||||||
53
examples/consumers/prompt_catalog.go
Normal file
53
examples/consumers/prompt_catalog.go
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
package consumers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PromptCatalogConfig is an application-owned prompt collection shape.
|
||||||
|
type PromptCatalogConfig struct {
|
||||||
|
Prompts []PromptRecord `yaml:"prompts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PromptRecord keeps its identity and message meaning in the consumer.
|
||||||
|
type PromptRecord struct {
|
||||||
|
ID string `yaml:"id"`
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Messages []string `yaml:"messages"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadPromptCatalog composes explicitly registered prompt records in the main
|
||||||
|
// tier and replaces the lower-priority default collection as a whole.
|
||||||
|
func LoadPromptCatalog(mainPath string) (*configkit.Result[PromptCatalogConfig], error) {
|
||||||
|
return configkit.LoadLayered(configkit.Input{
|
||||||
|
Source: configkit.File(mainPath),
|
||||||
|
Imports: true,
|
||||||
|
}, configkit.LayeredOptions[PromptCatalogConfig]{
|
||||||
|
Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{
|
||||||
|
Source: configkit.Bytes("default prompts", []byte("prompts:\n - id: default\n name: Default prompt\n messages: [Default message]\n")),
|
||||||
|
}}}},
|
||||||
|
Definition: configkit.Definition[PromptCatalogConfig]{
|
||||||
|
SequenceCompositions: []configkit.SequenceComposition{{
|
||||||
|
Path: configkit.Keys("prompts"),
|
||||||
|
IdentityField: "id",
|
||||||
|
}},
|
||||||
|
Validate: validatePromptCatalog,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func validatePromptCatalog(configuration *PromptCatalogConfig, validation *configkit.Validation) {
|
||||||
|
for index, prompt := range configuration.Prompts {
|
||||||
|
if strings.TrimSpace(prompt.Name) == "" {
|
||||||
|
validation.Error(configkit.Keys("prompts").Index(index).Key("name"), "must not be empty")
|
||||||
|
}
|
||||||
|
if len(prompt.Messages) == 0 {
|
||||||
|
validation.Error(configkit.Keys("prompts").Index(index).Key("messages"), "must contain at least one message")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(configuration.Prompts) == 0 {
|
||||||
|
validation.Error(configkit.Keys("prompts"), "must contain at least one prompt")
|
||||||
|
}
|
||||||
|
}
|
||||||
82
examples/consumers/prompt_catalog_test.go
Normal file
82
examples/consumers/prompt_catalog_test.go
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
package consumers_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
configkit "gitea.maximumdirect.net/eric/ConfigKit"
|
||||||
|
"gitea.maximumdirect.net/eric/ConfigKit/examples/consumers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Example_identifiedPromptCatalog() {
|
||||||
|
result, err := consumers.LoadPromptCatalog(fixture("prompt-catalog", "config.yml"))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ids := make([]string, 0, len(result.Config.Prompts))
|
||||||
|
for _, prompt := range result.Config.Prompts {
|
||||||
|
ids = append(ids, prompt.ID)
|
||||||
|
}
|
||||||
|
fmt.Println(ids, err)
|
||||||
|
// Output: [main curated weather welcome] <nil>
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPromptCatalogImportsRegisteredItemsAndReplacesDefaults(t *testing.T) {
|
||||||
|
result, err := consumers.LoadPromptCatalog(fixture("prompt-catalog", "config.yml"))
|
||||||
|
if err != nil {
|
||||||
|
var loadError *configkit.LoadError
|
||||||
|
if errors.As(err, &loadError) {
|
||||||
|
t.Fatalf("load prompt catalog: %v (%#v)", err, loadError.Diagnostics())
|
||||||
|
}
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(result.Config.Prompts) != 4 {
|
||||||
|
t.Fatalf("prompt records = %#v", result.Config.Prompts)
|
||||||
|
}
|
||||||
|
ids := []string{"main", "curated", "weather", "welcome"}
|
||||||
|
for index, id := range ids {
|
||||||
|
if result.Config.Prompts[index].ID != id {
|
||||||
|
t.Fatalf("prompt %d ID = %q, want %q", index, result.Config.Prompts[index].ID, id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, prompt := range result.Config.Prompts {
|
||||||
|
if prompt.ID == "default" {
|
||||||
|
t.Fatalf("lower-priority default survived main sequence replacement: %#v", result.Config.Prompts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var itemImports, helperImports int
|
||||||
|
for _, source := range result.Sources() {
|
||||||
|
switch filepath.Base(source.Path) {
|
||||||
|
case "curated.yml", "generated-weather.yml", "generated-welcome.yml":
|
||||||
|
if source.PlacementMode != configkit.PlacementModeSequenceItem || source.Destination.String() != "/prompts" {
|
||||||
|
t.Fatalf("item source placement = %#v", source)
|
||||||
|
}
|
||||||
|
itemImports++
|
||||||
|
case "curated-id.yml":
|
||||||
|
if source.PlacementMode != configkit.PlacementModeMapping || source.ImportedFrom == nil {
|
||||||
|
t.Fatalf("helper source = %#v", source)
|
||||||
|
}
|
||||||
|
helperImports++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if itemImports != 3 || helperImports != 1 {
|
||||||
|
t.Fatalf("item imports = %d, helper imports = %d, sources = %#v", itemImports, helperImports, result.Sources())
|
||||||
|
}
|
||||||
|
if result.Config.Prompts[1].ID != "curated" {
|
||||||
|
t.Fatalf("helper did not provide prompt ID: %#v", result.Config.Prompts[1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPromptCatalogLeavesDomainValidationWithConsumer(t *testing.T) {
|
||||||
|
_, err := consumers.LoadPromptCatalog(fixture("prompt-catalog", "invalid.yml"))
|
||||||
|
var loadError *configkit.LoadError
|
||||||
|
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 ||
|
||||||
|
loadError.Diagnostics()[0].Code != configkit.CodeValidateError ||
|
||||||
|
loadError.Diagnostics()[0].Path.String() != "/prompts/0/messages" {
|
||||||
|
t.Fatalf("consumer domain validation error = %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
12
examples/consumers/testdata/prompt-catalog/config.yml
vendored
Normal file
12
examples/consumers/testdata/prompt-catalog/config.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
configkit:
|
||||||
|
imports:
|
||||||
|
- path: prompts/curated.yml
|
||||||
|
destination: [prompts]
|
||||||
|
placement: sequence-item
|
||||||
|
- glob: prompts/generated-*.yml
|
||||||
|
destination: [prompts]
|
||||||
|
placement: sequence-item
|
||||||
|
prompts:
|
||||||
|
- id: main
|
||||||
|
name: Main authored prompt
|
||||||
|
messages: [Use the main prompt.]
|
||||||
4
examples/consumers/testdata/prompt-catalog/invalid.yml
vendored
Normal file
4
examples/consumers/testdata/prompt-catalog/invalid.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
prompts:
|
||||||
|
- id: invalid
|
||||||
|
name: Invalid prompt
|
||||||
|
messages: []
|
||||||
1
examples/consumers/testdata/prompt-catalog/prompts/curated-id.yml
vendored
Normal file
1
examples/consumers/testdata/prompt-catalog/prompts/curated-id.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
id: curated
|
||||||
6
examples/consumers/testdata/prompt-catalog/prompts/curated.yml
vendored
Normal file
6
examples/consumers/testdata/prompt-catalog/prompts/curated.yml
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
configkit:
|
||||||
|
imports:
|
||||||
|
- path: curated-id.yml
|
||||||
|
name: Curated summary
|
||||||
|
messages:
|
||||||
|
- Summarize the supplied content.
|
||||||
4
examples/consumers/testdata/prompt-catalog/prompts/generated-weather.yml
vendored
Normal file
4
examples/consumers/testdata/prompt-catalog/prompts/generated-weather.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
id: weather
|
||||||
|
name: Weather forecast
|
||||||
|
messages:
|
||||||
|
- Describe today's forecast.
|
||||||
4
examples/consumers/testdata/prompt-catalog/prompts/generated-welcome.yml
vendored
Normal file
4
examples/consumers/testdata/prompt-catalog/prompts/generated-welcome.yml
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
id: welcome
|
||||||
|
name: Welcome
|
||||||
|
messages:
|
||||||
|
- Welcome the user.
|
||||||
Reference in New Issue
Block a user