Clarify ConfigKit prerequisites and efficiency goals

This commit is contained in:
2026-09-29 14:52:38 +00:00
parent c7bdaa076b
commit 37f8dba6c3

View File

@@ -1,7 +1,8 @@
# ConfigKit Adoption Assessment # ConfigKit Adoption Assessment
Status: proposed for discussion, not an approved feature specification or an Status: assessment with agreed design direction; upstream API details remain
implementation plan. No runtime changes are part of this assessment. to be settled before the feature roadmap and implementation plan. No runtime
changes are part of this assessment.
## Goal And Recommendation ## Goal And Recommendation
@@ -24,6 +25,41 @@ lazy error arbitration, and repeated profile-chain resolution. Some of those
savings come from the loading redesign rather than ConfigKit itself. ConfigKit savings come from the loading redesign rather than ConfigKit itself. ConfigKit
adds ongoing value by owning the generic decoding behavior and its tests. adds ongoing value by owning the generic decoding behavior and its tests.
## Prerequisite: Proposed Upstream ConfigKit Work
Design, implement, and release these two ConfigKit capabilities before the
dependent PromptKit refactor. The remaining recommendations assume this upstream
work; finalize their integration details against its agreed public contracts.
These are selected architectural prerequisites, not a claim that adoption is
technically impossible using today's reader-based API.
1. **Native `fs.FS` sources and source-relative context.** Support embedded and
caller-supplied filesystems as first-class configuration sources. Define source
identity, relative path resolution, ownership, and how enabled imports and
overlays operate within that filesystem. This is broadly useful for libraries
bundling default configuration. Passing an opened file to today's `Reader`
supplies bytes and a label, but does not make filesystem-relative loading
native to ConfigKit; that workaround is not the target architecture.
2. **Public in-memory layered loading with origins.** Support explicitly supplied
layers without temporary files or YAML serialization round trips, retaining
presence and meaningful source provenance. The upstream design must settle
which inputs it accepts: filesystem/byte sources, typed values, or both; how
typed values express omission; and how strict composition differs from
intentional overriding. Recommend covering embedded defaults, caller sources,
and programmatic values, with explicit ordering and useful conflict diagnostics.
Keep these APIs application-neutral. A list of sources alone does not implement
PromptKit's whole-profile shadowing, named inheritance, or atomic provider maps.
Define which layer operations ConfigKit owns and which identity/domain decisions
remain in PromptKit; do not silently substitute recursive merging for an agreed
replacement rule. Revisit ConfigKit's current single-overlay/deferred boundaries
deliberately rather than working around them inside PromptKit.
The upstream design should show how the two capabilities work together, including
source origins and efficient ownership/copying. Resolve these API questions before
turning the assessment into a decision-complete PromptKit implementation plan.
This assessment does not authorize code changes in either repository.
## Evidence And Scope ## Evidence And Scope
Reviewed local baselines on 2026-09-29: Reviewed local baselines on 2026-09-29:
@@ -80,7 +116,8 @@ dropping execution features to simplify the configuration layer.
| YAML grammar, scalar interpretation, one-document enforcement, unknown fields, typed ranges, null legality | Delegate to ConfigKit; remove corresponding PromptKit parser logic and redundant parser tests | | YAML grammar, scalar interpretation, one-document enforcement, unknown fields, typed ranges, null legality | Delegate to ConfigKit; remove corresponding PromptKit parser logic and redundant parser tests |
| Field presence and source coordinates | Delegate to ConfigKit; retain only the compact records needed for resolution and diagnostics | | Field presence and source coordinates | Delegate to ConfigKit; retain only the compact records needed for resolution and diagnostics |
| File/directory/embedded source selection and definition ID indexing | Retain a small PromptKit collection loader; ConfigKit loads documents, not a prompt catalog | | File/directory/embedded source selection and definition ID indexing | Retain a small PromptKit collection loader; ConfigKit loads documents, not a prompt catalog |
| Filesystem traversal and relative content references | Retain PromptKit's source-boundary adapters; use standard `io/fs` facilities where sufficient | | Configuration filesystem sources, relative imports, and generic layer origins | Delegate to the prerequisite ConfigKit APIs; do not maintain parallel reader-based loading machinery |
| Definition discovery and relative message-content references | Retain PromptKit's domain resource adapters, using ConfigKit source context and standard `io/fs` facilities where sufficient |
| Profile-source priority and duplicate definition policy | Retain explicit PromptKit collection assembly; eliminate error-driven repository fallback | | Profile-source priority and duplicate definition policy | Retain explicit PromptKit collection assembly; eliminate error-driven repository fallback |
| Named profile inheritance and backend selection | Retain a typed PromptKit resolver over the loaded collection, with explicit presence; consider generic inheritance upstream only with broader evidence | | Named profile inheritance and backend selection | Retain a typed PromptKit resolver over the loaded collection, with explicit presence; consider generic inheritance upstream only with broader evidence |
| LLM setting bounds, role/session normalization, output rules, reserved provider fields | Retain shared PromptKit domain owners; ConfigKit validation callbacks may invoke them | | LLM setting bounds, role/session normalization, output rules, reserved provider fields | Retain shared PromptKit domain owners; ConfigKit validation callbacks may invoke them |
@@ -106,10 +143,11 @@ belongs in this phase. Publish no partially initialized engine on failure.
Use one typed document per prompt or profile initially. Existing files need not Use one typed document per prompt or profile initially. Existing files need not
be converted into a monolithic application configuration merely to adopt be converted into a monolithic application configuration merely to adopt
ConfigKit. Support OS directories, individual files, embedded/custom `fs.FS` ConfigKit. Support OS directories, individual files, embedded/custom `fs.FS`
sources, and programmatic profiles. For `fs.FS`, a small adapter can open a file sources, and programmatic profiles. Use the prerequisite native ConfigKit
and supply `configkit.Reader` with a safe source label; PromptKit retains root filesystem and layered-loading APIs for configuration acquisition and generic
and path context for referenced message files. Close handles owned by the adapter. composition. PromptKit retains definition discovery and message-resource handling,
ConfigKit's existing public API is sufficient for this design. using the source context supplied by ConfigKit. Exact integration is contingent
on the upstream contracts; do not build a competing layer engine in PromptKit.
Load and freeze referenced message text with definitions. Validate static prompt Load and freeze referenced message text with definitions. Validate static prompt
structure and template syntax at loading, using the same template function setup structure and template syntax at loading, using the same template function setup
@@ -147,10 +185,12 @@ requirements after runtime selection/overrides. Prompt default-profile reference
can be checked against the assembled collection; a prompt with no default remains can be checked against the assembled collection; a prompt with no default remains
valid for callers that supply a profile explicitly. valid for callers that supply a profile explicitly.
This is named-definition precedence, not ConfigKit's application overlay system. Named-definition precedence is distinct from recursive application overlays.
Do not generate temporary overlay files or serialize maps to YAML to imitate a Use the upstream layered API where its operations fit; retain the small identity
missing layer API. ConfigKit imports are also not directory discovery: their selection step in PromptKit where needed. The upstream design must make that
strict composition has different semantics and need not be enabled here. boundary explicit. Do not generate temporary overlay files or serialize maps to
YAML to imitate a missing operation. Imports are not definition discovery and
need not be enabled merely because native filesystem sources support them.
### Inheritance And Presence ### Inheritance And Presence
@@ -250,16 +290,44 @@ resolved values. ConfigKit also creates metadata and projections; keep only need
records after loading. These are reasoned tradeoffs, not measured performance records after loading. These are reasoned tradeoffs, not measured performance
claims. Adoption is not justified by the decoder replacement alone. claims. Adoption is not justified by the decoder replacement alone.
## 5. Upstream Opportunities ### Algorithmic Efficiency
No ConfigKit enhancement is a demonstrated prerequisite for the recommended Efficiency is an explicit design criterion for both the upstream work and this
per-document snapshot design. Do not manufacture one to move a small adapter shared-library refactor. Prefer optimal or near-optimal algorithms relative to
upstream. Reconsider the following if the agreed roadmap reveals concrete reuse: input and produced-data size, not a blanket O(n) claim with an undefined n.
- Acquire and decode each definition once per snapshot; reuse captured content
rather than reopening or reparsing it for metadata, selection, and validation.
- Build identity indexes in one pass, with expected constant-time map lookup.
Do not scan whole collections for every lookup or precedence decision.
- Process inheritance graph structure in O(V + E), where V is the number of
profiles and E the inheritance edges. Resolve shared ancestors once. Account
separately for the size of materialized settings and retained origins; copying
large inherited maps to many independent results necessarily costs more than V.
- Avoid whole-collection copying per layer, repeated serialization, and repeated
prefix/history traversal. Analyze layer processing against total input nodes
and produced values/provenance, including intentionally retained history.
- Keep configuration discovery and decoding out of ordinary execution. Copy only
where ownership requires it; do not trade caller isolation for speed.
These are design targets, not promised complexity for every operation. Sorting
for deterministic discovery may require O(F log F) for F files, and processing
message text costs work proportional to its bytes. Construction time, retained
memory, and frequent-call costs all matter. Prefer straightforward indexes and
clear immutable ownership over speculative global caches or intricate optimizers.
The implementation plan should include focused benchmarks for consequential
repeated-work risks, such as shared-ancestor profiles and many layers, rather than
machine-dependent timing gates or benchmarks for every helper.
## 5. Additional Upstream Opportunities
Native filesystem sources and public layered loading with origins are the
prerequisites described near the beginning, not optional follow-ups. The following
remain optional and do not block adoption unless the upstream design establishes
a concrete dependency:
| Candidate | Recommendation and tradeoff | | Candidate | Recommendation and tradeoff |
| --- | --- | | --- | --- |
| Native `fs.FS` sources with source-relative resource context | Most plausible optional enhancement: embedded configurations are useful across Go libraries. Reader sources suffice today. A fuller design must define imports/overlays in that filesystem rather than merely add a constructor or leak parser internals. |
| Public in-memory layered loading with origins | Optional only if multiple consumers need application defaults and file/embedded layers composed together. It could remove adapters in those consumers, but is not necessary for whole-definition catalog shadowing. Review against ConfigKit's deliberate single-overlay scope. |
| Generic named inheritance/presence-aware typed overlay | Consider an upstream proposal if a coherent application-neutral operation emerges; another concrete use case would strengthen the case but is not a prerequisite. PromptKit's named graph, atomic provider map, and routing rules alone do not justify a configurable general merge framework. Current fixed overlay semantics are not this API. | | Generic named inheritance/presence-aware typed overlay | Consider an upstream proposal if a coherent application-neutral operation emerges; another concrete use case would strengthen the case but is not a prerequisite. PromptKit's named graph, atomic provider map, and routing rules alone do not justify a configurable general merge framework. Current fixed overlay semantics are not this API. |
| Context-aware loading | Optional for reusable cancellable construction if large-source consumers need it. Promise cooperative cancellation only; no detached reads or instant interruption of arbitrary readers. | | Context-aware loading | Optional for reusable cancellable construction if large-source consumers need it. Promise cooperative cancellation only; no detached reads or instant interruption of arbitrary readers. |
@@ -272,12 +340,15 @@ ConfigKit and PromptKit both declare LGPL-3.0-or-later. Adoption must still upda
dependency notices under the OSS policy and inspect the exact selected release dependency notices under the OSS policy and inspect the exact selected release
and its transitive notices. Their current Go minimums do not require a PromptKit and its transitive notices. Their current Go minimums do not require a PromptKit
toolchain increase. Use a released module dependency, not a sibling-directory toolchain increase. Use a released module dependency, not a sibling-directory
replacement. This review proposes no licensing change or upstream edits. replacement. This assessment proposes upstream work, but makes no upstream edits
or licensing change.
## 6. Decisions And Migration ## 6. Decisions And Migration
The goal and permission to break compatibility are agreed. The following specific The goal, permission to break compatibility, and these four recommendations are
choices are recommendations for discussion, not inferred approvals: the agreed working direction. Alternatives remain recorded for rationale, not as
unresolved votes. The prerequisite upstream API questions remain open and must be
settled before finalizing dependent implementation details.
1. **Loading lifetime and failure scope.** Recommend eager construction, frozen 1. **Loading lifetime and failure scope.** Recommend eager construction, frozen
definitions/content, and failure for malformed files anywhere in supplied definitions/content, and failure for malformed files anywhere in supplied
@@ -326,8 +397,9 @@ Expected consumer migration:
literals as required. Keep representative preparation, execution, inspection, literals as required. Keep representative preparation, execution, inspection,
custom backend, fallback, and embedded workflows in the migration guidance. custom backend, fallback, and embedded workflows in the migration guidance.
The subsequent feature roadmap should settle these choices and specify the target The subsequent feature roadmap should carry forward these choices, resolve the
end state. The staged implementation plan can then sequence any accepted upstream upstream API details, and specify the target end state. The staged implementation
work, PromptKit deletions/replacements, contract tests, canonical documentation, plan must sequence the prerequisite ConfigKit releases before dependent PromptKit
work, then cover deletions/replacements, contract tests, canonical documentation,
examples, attribution, and minor-release migration notes. Neither document should examples, attribution, and minor-release migration notes. Neither document should
become a reason to preserve obsolete compatibility machinery. become a reason to preserve obsolete compatibility machinery.