Accept the ConfigKit configuration boundary and align the implementation plan
This commit is contained in:
60
docs/adr/0001-configuration-boundary.md
Normal file
60
docs/adr/0001-configuration-boundary.md
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# 0001: Configuration Ownership At The ConfigKit Handoff
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Accepted.
|
||||||
|
|
||||||
|
## Date
|
||||||
|
|
||||||
|
2026-09-30
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
PromptKit is adopting ConfigKit to standardize configuration semantics and
|
||||||
|
simplify its loading machinery. Configuration includes prompts, profiles, and
|
||||||
|
backend definitions contributed by maintained catalogs and consuming applications.
|
||||||
|
ConfigKit supplies loading, composition, precedence, inheritance, and inspection
|
||||||
|
capabilities. PromptKit supplies LLM-specific interpretation and execution.
|
||||||
|
|
||||||
|
A clear handoff assigns each library responsibility for the configuration it
|
||||||
|
owns and keeps validation aligned with the values an application actually uses.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
ConfigKit owns configuration processing up to the handoff of the final effective
|
||||||
|
configuration. PromptKit takes ownership at that handoff and applies its domain
|
||||||
|
interpretation and validation to the final configuration.
|
||||||
|
|
||||||
|
The handoff includes effective presence/null information and resource context
|
||||||
|
supplied by ConfigKit. PromptKit uses this information to interpret effective
|
||||||
|
settings and resolve referenced resources.
|
||||||
|
|
||||||
|
PromptKit passes through ConfigKit's inspection capabilities for explicit
|
||||||
|
operator use. Configuration history and source explanations serve that
|
||||||
|
inspection purpose; domain validation operates on the final effective values.
|
||||||
|
|
||||||
|
This boundary applies uniformly to application configuration and maintained
|
||||||
|
catalog configuration, including backend definitions.
|
||||||
|
|
||||||
|
## Alternatives Considered
|
||||||
|
|
||||||
|
- **Independent source or catalog preflight validation:** preserves checks on
|
||||||
|
individual contributions, but duplicates configuration processing and evaluates
|
||||||
|
values that may be replaced before handoff. Raw-source and intermediate-state
|
||||||
|
validation are outside PromptKit's scope, including equivalent test-only checks.
|
||||||
|
- **History-based source auditing:** can identify overwritten contributions, but
|
||||||
|
couples domain enforcement to configuration history. Historical inspection is
|
||||||
|
an operator capability rather than a validation mechanism.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
PromptKit's configuration logic and tests focus on the final effective values,
|
||||||
|
their domain meaning, and resulting execution behavior. ConfigKit owns failures
|
||||||
|
arising during its processing, which PromptKit preserves through its error
|
||||||
|
boundary. Catalog maintainers own their repositories' publishing checks.
|
||||||
|
|
||||||
|
The adoption work routes backend configuration through the same handoff and
|
||||||
|
retires PromptKit's source-level and intermediate-configuration validation.
|
||||||
|
Effective resource interpretation and explicit operator inspection remain
|
||||||
|
supported. This concentrates configuration semantics in ConfigKit and reduces
|
||||||
|
duplicated machinery and maintenance in PromptKit.
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
# ConfigKit Adoption
|
# ConfigKit Adoption
|
||||||
|
|
||||||
Status: agreed feature roadmap. ConfigKit v0.5.0 supplies the required upstream
|
Status: agreed feature roadmap. ConfigKit v0.5.0 supplies the required upstream
|
||||||
capabilities. The [implementation plan](implementation.md) owns execution steps
|
capabilities. The [implementation plan](implementation.md) owns execution steps.
|
||||||
and identifies one remaining catalog-validation placement decision. This document
|
The [configuration-boundary ADR](../adr/0001-configuration-boundary.md) records
|
||||||
owns the intended end state, not implementation authorization.
|
the handoff decision. This document owns the intended end state, not
|
||||||
|
implementation authorization.
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
@@ -70,18 +71,23 @@ exist. Domain validation must not probe provider/model availability.
|
|||||||
|
|
||||||
### One Shared Loading Lifecycle
|
### One Shared Loading Lifecycle
|
||||||
|
|
||||||
Construction acquires configuration contributions, uses ConfigKit to compose and
|
Construction supplies selected configuration inputs to ConfigKit, which composes,
|
||||||
overlay them, expands sibling inheritance, decodes the effective configuration,
|
overlays, expands inheritance, and decodes them. PromptKit interprets and validates
|
||||||
performs recorded domain resolution and validation, and produces execution-ready
|
the final effective configuration at the ConfigKit handoff and produces
|
||||||
definitions. Publish no partially initialized engine on failure.
|
execution-ready definitions. ConfigKit's effective-value resolution and validation
|
||||||
|
hooks may implement that handoff. Publish no partially initialized engine on failure.
|
||||||
|
|
||||||
ConfigKit owns generic parsing, combination, presence, origins, and inheritance.
|
ConfigKit owns generic parsing, combination, presence, origins, and inheritance.
|
||||||
PromptKit owns source selection/discovery, definition indexing, backend policy,
|
PromptKit owns input selection/discovery, definition indexing, LLM-specific rules,
|
||||||
LLM-specific rules, and translation into runtime values. Runtime clients and
|
and translation of final values into runtime settings. Input adapters select or
|
||||||
callbacks remain normal Go dependencies, not YAML configuration types.
|
encode contributions; they do not inspect or validate raw source contents.
|
||||||
|
Effective presence/null information and resource context supplied by ConfigKit
|
||||||
|
support interpretation at handoff. Historical inspection remains an explicitly
|
||||||
|
invoked operator capability, separate from domain enforcement.
|
||||||
|
Runtime clients and callbacks remain normal Go dependencies, not YAML types.
|
||||||
|
|
||||||
Use `profiles.<id>` and `prompts.<id>.<version>` keyed mappings assembled before
|
Use `backends.<id>`, `profiles.<id>`, and `prompts.<id>.<version>` keyed mappings
|
||||||
typed decoding rather than independently decoding definitions and combining them
|
assembled before typed decoding rather than independently decoding definitions and combining them
|
||||||
afterward. Keys own identity; do not duplicate `id`/`version` fields. These paths
|
afterward. Keys own identity; do not duplicate `id`/`version` fields. These paths
|
||||||
describe mapping levels, not dot-splitting of literal IDs or version keys.
|
describe mapping levels, not dot-splitting of literal IDs or version keys.
|
||||||
Multiple files can contribute to a collection; a monolithic file is not required.
|
Multiple files can contribute to a collection; a monolithic file is not required.
|
||||||
@@ -96,7 +102,11 @@ Accept ConfigKit's labeled mapping sources for programmatic configuration. Add
|
|||||||
only small typed conveniences justified by the minimal local-backend and
|
only small typed conveniences justified by the minimal local-backend and
|
||||||
application-profile workflows. Helpers encode explicit presence and feed the same
|
application-profile workflows. Helpers encode explicit presence and feed the same
|
||||||
loading lifecycle; they neither merge configurations nor infer omission from zeros.
|
loading lifecycle; they neither merge configurations nor infer omission from zeros.
|
||||||
HTTP/model clients and other runtime collaborators remain outside typed configuration.
|
Backend helpers also produce inputs to this lifecycle. Backend definitions,
|
||||||
|
including catalog connection and capacity settings, cross the same ConfigKit
|
||||||
|
handoff as prompts and profiles. The immutable runtime registry is built from
|
||||||
|
effective backend values. HTTP/model clients and other runtime collaborators
|
||||||
|
remain outside typed configuration.
|
||||||
|
|
||||||
Keep the public package a deliberate facade and implementation private. Do not
|
Keep the public package a deliberate facade and implementation private. Do not
|
||||||
expose internal engine/domain types or introduce a parallel generic loader merely
|
expose internal engine/domain types or introduce a parallel generic loader merely
|
||||||
@@ -110,12 +120,15 @@ programmatic definitions. Explicitly selected directories may be discovered by
|
|||||||
PromptKit; ConfigKit handles their configuration contributions. Do not infer
|
PromptKit; ConfigKit handles their configuration contributions. Do not infer
|
||||||
priority from traversal order.
|
priority from traversal order.
|
||||||
|
|
||||||
Retain the useful profile priority categories, lowest to highest: external
|
Retain the useful priority categories, lowest to highest: external
|
||||||
catalogs, PromptKit-owned profiles, application fallback, operator configuration,
|
catalogs, PromptKit-owned profiles, application fallback, operator configuration,
|
||||||
and programmatic configuration. Express intentional priority as ordered tiers.
|
and programmatic configuration. Express intentional priority as ordered tiers.
|
||||||
Within each tier, independent contributions compose strictly; overlapping
|
Within each tier, independent contributions compose strictly; overlapping
|
||||||
non-mapping values conflict, even when equal. Disjoint fields under the same
|
non-mapping values conflict, even when equal. Disjoint fields under the same
|
||||||
identity can combine. Across tiers, mappings recursively overlay.
|
identity can combine. Across tiers, mappings recursively overlay.
|
||||||
|
These rules also govern backend configuration; consumers can add backend IDs or
|
||||||
|
overlay existing definitions through their selected tiers. Registry construction
|
||||||
|
validates the resulting values, not the identity of their contributors.
|
||||||
|
|
||||||
Use ConfigKit's source roles honestly: underlay groups are ordered defaults,
|
Use ConfigKit's source roles honestly: underlay groups are ordered defaults,
|
||||||
main input overlays underlays, and optional named overlay/CLI facilities retain
|
main input overlays underlays, and optional named overlay/CLI facilities retain
|
||||||
@@ -155,11 +168,14 @@ Document and test this distinction, including any affected maintained payloads.
|
|||||||
|
|
||||||
### Validation And Errors
|
### Validation And Errors
|
||||||
|
|
||||||
Source acquisition, syntax, and strict-composition failures cannot be masked by
|
ConfigKit owns acquisition, syntax, composition, inheritance, and typed-decoding
|
||||||
higher tiers. Typed and semantic validation apply to effective values rather than
|
failures. PromptKit preserves those errors and validates final effective domain
|
||||||
every intermediate layer. An unused invalid effective definition fails construction.
|
values. An unused invalid effective definition fails construction; a lower-layer
|
||||||
Separate catalog ownership/reserved-name/secret-safety checks remain source-policy
|
value legitimately replaced by ConfigKit is not a separate validation target.
|
||||||
responsibilities, not justification for duplicate generic decoding.
|
This boundary applies equally to application and maintained catalog configuration.
|
||||||
|
PromptKit does not perform catalog preflight, raw-source or intermediate-state
|
||||||
|
validation, or history-based enforcement, including equivalent test-only checks.
|
||||||
|
Catalog maintainers own publishing checks in their respective repositories.
|
||||||
|
|
||||||
Domain validators remain shared with runtime request validation where appropriate.
|
Domain validators remain shared with runtime request validation where appropriate.
|
||||||
Allow schema-valid partial profiles without an `abstract` flag. Validate supplied
|
Allow schema-valid partial profiles without an `abstract` flag. Validate supplied
|
||||||
@@ -246,13 +262,18 @@ or configuration content safe to publish.
|
|||||||
- Remove the custom profile inheritance resolver and error-driven repository
|
- Remove the custom profile inheritance resolver and error-driven repository
|
||||||
overlay stack. Do not retain an old-format compatibility engine alongside the
|
overlay stack. Do not retain an old-format compatibility engine alongside the
|
||||||
new semantics.
|
new semantics.
|
||||||
|
- Route catalog and programmatic backend definitions through ConfigKit; retire
|
||||||
|
the separate backend-manifest decoder and pre-handoff registration validation.
|
||||||
|
Retain backend endpoint, capacity, and provider-parameter domain validation on
|
||||||
|
the final effective values.
|
||||||
- Retain only needed discovery and message-resource adapters; remove direct YAML
|
- Retain only needed discovery and message-resource adapters; remove direct YAML
|
||||||
dependency usage once no remaining owner needs it. Preserve JSON Schema,
|
dependency usage once no remaining owner needs it. Preserve JSON Schema,
|
||||||
runtime JSON-value ownership, domain validation, and execution collaborators.
|
runtime JSON-value ownership, domain validation, and execution collaborators.
|
||||||
- Adapt maintained catalogs and PromptKit-owned definitions to the agreed keyed
|
- Adapt maintained catalogs and PromptKit-owned definitions to the agreed keyed
|
||||||
format and released inheritance semantics. Preserve maintained name commitments,
|
format and released inheritance semantics, including keyed backend assets.
|
||||||
backend ownership, and catalog namespace rules without upstream availability
|
Preserve maintained name commitments and the intended shipped backend settings.
|
||||||
checks. Coordinate necessary catalog releases before consuming their new format.
|
Catalog source-policy enforcement belongs to catalog maintainers. Coordinate
|
||||||
|
compatible catalog releases before consuming the changed asset format.
|
||||||
Publish new keyed assets directly in the existing data-only catalog projects,
|
Publish new keyed assets directly in the existing data-only catalog projects,
|
||||||
recording the format transition rather than maintaining duplicate legacy assets
|
recording the format transition rather than maintaining duplicate legacy assets
|
||||||
or a permanent conversion adapter. Catalog maintainers select release/version
|
or a permanent conversion adapter. Catalog maintainers select release/version
|
||||||
@@ -282,7 +303,9 @@ the requested report; that work remains off the execution path.
|
|||||||
Tests should use real ConfigKit with offline sources and synthetic provider
|
Tests should use real ConfigKit with offline sources and synthetic provider
|
||||||
collaborators. PromptKit owns its adapter, domain, lifecycle, and execution tests,
|
collaborators. PromptKit owns its adapter, domain, lifecycle, and execution tests,
|
||||||
not a duplicate ConfigKit parser/graph suite. Retire tests whose only purpose was
|
not a duplicate ConfigKit parser/graph suite. Retire tests whose only purpose was
|
||||||
the removed loading machinery. Preserve meaningful execution regressions.
|
the removed loading machinery or source-policy enforcement. Exercise catalog
|
||||||
|
integration through the final assembled configuration and resulting behavior.
|
||||||
|
Preserve meaningful execution regressions.
|
||||||
|
|
||||||
Representative acceptance evidence must cover:
|
Representative acceptance evidence must cover:
|
||||||
|
|
||||||
@@ -305,7 +328,8 @@ release gates or provider-network tests.
|
|||||||
Ship as an intentionally incompatible minor release with concrete migration
|
Ship as an intentionally incompatible minor release with concrete migration
|
||||||
guidance. Cover keyed files, `base_profile` to `extends`, reserved-key behavior,
|
guidance. Cover keyed files, `base_profile` to `extends`, reserved-key behavior,
|
||||||
recursive maps, explicit null versus omission, changed error timing, programmatic
|
recursive maps, explicit null versus omission, changed error timing, programmatic
|
||||||
construction, and explicit engine replacement. Explain that overriding a model
|
construction, backend layering in place of registration-only restrictions, and
|
||||||
|
explicit engine replacement. Explain that overriding a model
|
||||||
does not discard lower endpoint, reasoning, provider, or inheritance settings.
|
does not discard lower endpoint, reasoning, provider, or inheritance settings.
|
||||||
|
|
||||||
The end state is one shared configuration model with the old loading/resolution
|
The end state is one shared configuration model with the old loading/resolution
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# ConfigKit Adoption Implementation Plan
|
# ConfigKit Adoption Implementation Plan
|
||||||
|
|
||||||
Status: ready for staged implementation, except for the explicitly identified
|
Status: ready for staged implementation under the agreed configuration boundary.
|
||||||
catalog-validation decision under Open Questions. This is a planning document;
|
This is a planning document; writing it does not implement the feature or
|
||||||
writing it does not implement the feature or authorize publishing dependencies.
|
authorize publishing dependencies.
|
||||||
|
|
||||||
## Authority And Working Method
|
## Authority And Working Method
|
||||||
|
|
||||||
@@ -10,6 +10,12 @@ The [ConfigKit feature roadmap](configkit.md) owns the intended end state and
|
|||||||
approved policy. Its intentional-breaking-change direction is authoritative:
|
approved policy. Its intentional-breaking-change direction is authoritative:
|
||||||
preserve substantive prompting capabilities, not the old loader, signatures,
|
preserve substantive prompting capabilities, not the old loader, signatures,
|
||||||
source wrappers, incidental error ordering, or configuration syntax.
|
source wrappers, incidental error ordering, or configuration syntax.
|
||||||
|
The [configuration-boundary ADR](../adr/0001-configuration-boundary.md) records
|
||||||
|
the ownership decision: PromptKit interprets and validates the final effective
|
||||||
|
configuration supplied by ConfigKit. Presence/null information and effective
|
||||||
|
resource context are part of that handoff. Source history serves explicit
|
||||||
|
operator inspection, not validation or catalog enforcement. This applies to
|
||||||
|
tests as well as production code.
|
||||||
|
|
||||||
Implement the stages below in order, one stage per coding-agent prompt. Each
|
Implement the stages below in order, one stage per coding-agent prompt. Each
|
||||||
stage includes its tests and affected current-state documentation. Read
|
stage includes its tests and affected current-state documentation. Read
|
||||||
@@ -37,9 +43,12 @@ Planning baselines:
|
|||||||
|
|
||||||
Use ConfigKit v0.5.0 for this work. Do not silently upgrade to a different
|
Use ConfigKit v0.5.0 for this work. Do not silently upgrade to a different
|
||||||
contract. The catalog asset migration needs coordinated releases, not a committed
|
contract. The catalog asset migration needs coordinated releases, not a committed
|
||||||
workspace or local replacement. Exact catalog release versions are selected at
|
workspace or local replacement. Changing the backend asset contract is broader
|
||||||
publication under their existing date-based policy; record the versions and full
|
than the catalog profile-data compatibility exception: migrate the catalogs to
|
||||||
commits actually consumed. Publishing any repository requires separate authority.
|
`/v3` with `v3.YYYYMMDD.N` tags, preserving their date/revision convention and
|
||||||
|
updating their own release documentation accordingly. Select exact dates and
|
||||||
|
unused revisions at publication; record versions and full commits consumed.
|
||||||
|
Publishing any repository requires separate authority.
|
||||||
|
|
||||||
## Implementation Decisions
|
## Implementation Decisions
|
||||||
|
|
||||||
@@ -83,9 +92,10 @@ Use one ConfigKit filesystem namespace per helper invocation and root resource
|
|||||||
contexts at the supplied directory. Single files use ConfigKit directly.
|
contexts at the supplied directory. Single files use ConfigKit directly.
|
||||||
|
|
||||||
Remove `WithPromptFS`, `WithPromptFile`, `WithProfileFS`, `WithProfileFile`,
|
Remove `WithPromptFS`, `WithPromptFile`, `WithProfileFS`, `WithProfileFile`,
|
||||||
`WithFallbackProfileFS`, and `WithProfiles` at public cutover. Retain schema source
|
`WithFallbackProfileFS`, `WithProfiles`, and `WithBackend` at public cutover.
|
||||||
options and collaborator/backend injection. Do not require any prompts to exist
|
Retain schema source options and runtime collaborator injection. Backend
|
||||||
merely to construct an engine for profile inspection.
|
configuration moves into ConfigKit inputs as specified below. Do not require any
|
||||||
|
prompts to exist merely to construct an engine for profile inspection.
|
||||||
|
|
||||||
Programmatic configuration uses labeled `configkit.Mapping` inputs. Replace the
|
Programmatic configuration uses labeled `configkit.Mapping` inputs. Replace the
|
||||||
old zero-sentinel `Profile`/`OpenAICompatibleProfileConfig` pair with one small
|
old zero-sentinel `Profile`/`OpenAICompatibleProfileConfig` pair with one small
|
||||||
@@ -109,13 +119,36 @@ clear operation. Use raw Mapping for explicit null, prompt definitions, or riche
|
|||||||
configuration. Do not introduce a public generic optional-value type just for
|
configuration. Do not introduce a public generic optional-value type just for
|
||||||
this helper. Convert fields explicitly to ConfigKit-supported built-in values,
|
this helper. Convert fields explicitly to ConfigKit-supported built-in values,
|
||||||
then call Mapping for snapshot ownership and load-time errors. Do not marshal
|
then call Mapping for snapshot ownership and load-time errors. Do not marshal
|
||||||
through YAML or infer absence from a value. Keep the existing local-backend
|
through YAML or infer absence from a value. Helpers encode values; domain
|
||||||
constructor, which configures runtime backend registration rather than profiles.
|
validation occurs on the final configuration at handoff.
|
||||||
|
|
||||||
|
Replace the registration-only Backend value with a presence-aware convenience:
|
||||||
|
|
||||||
|
```go
|
||||||
|
type BackendConfig struct {
|
||||||
|
Endpoint, APIKeyEnv *string
|
||||||
|
ConcurrencyLimit, QueueCapacity *int
|
||||||
|
ExtraParams map[string]any
|
||||||
|
}
|
||||||
|
func BackendSource(label string, backends map[string]BackendConfig) configkit.Source
|
||||||
|
func LocalBackend(endpoint string, concurrencyLimit int) BackendConfig
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the same omission/pointer/map conventions as ProfileSource. LocalBackend
|
||||||
|
supplies endpoint and concurrency pointers and leaves the remaining fields
|
||||||
|
omitted; callers choose the ID as the map key. Neither helper validates settings
|
||||||
|
before ConfigKit processes them. For example, place BackendSource with
|
||||||
|
`map[string]BackendConfig{"local": LocalBackend(endpoint, 4)}` in an application
|
||||||
|
underlay. Raw Mapping supports explicit null and combined backend/profile/prompt
|
||||||
|
documents. Remove the old Backend registration value and its reservation rules;
|
||||||
|
retain useful built-in ID constants. All backend contributions follow the same
|
||||||
|
strict-composition and overlay rules as other configuration.
|
||||||
|
|
||||||
### Typed Configuration And Execution Values
|
### Typed Configuration And Execution Values
|
||||||
|
|
||||||
Add `internal/configuration` as the cohesive ConfigKit adapter. Its private
|
Add `internal/configuration` as the cohesive ConfigKit adapter. Its private
|
||||||
document DTO has `profiles: map[string]profileConfig` and
|
document DTO has `backends: map[string]backendConfig`,
|
||||||
|
`profiles: map[string]profileConfig`, and
|
||||||
`prompts: map[string]map[string]promptConfig`. Collection entries are mappings,
|
`prompts: map[string]map[string]promptConfig`. Collection entries are mappings,
|
||||||
not nullable definition pointers. No duplicate identity fields; ConfigKit consumes
|
not nullable definition pointers. No duplicate identity fields; ConfigKit consumes
|
||||||
`extends`, so no DTO field or second resolver handles it. Use `configkit.Keys`,
|
`extends`, so no DTO field or second resolver handles it. Use `configkit.Keys`,
|
||||||
@@ -128,6 +161,27 @@ private execution-owned fields or presence bits, not retained metadata queries.
|
|||||||
Runtime/domain packages must not import ConfigKit. Do not duplicate its tree,
|
Runtime/domain packages must not import ConfigKit. Do not duplicate its tree,
|
||||||
merge engine, inheritance graph, diagnostics, or presence framework.
|
merge engine, inheritance graph, diagnostics, or presence framework.
|
||||||
|
|
||||||
|
Backend DTO fields match BackendConfig using `endpoint`, `api_key_env`,
|
||||||
|
`concurrency_limit`, `queue_capacity`, and `extra_params`. Validate the final
|
||||||
|
endpoint as required, absolute HTTP(S) with the existing URL rules. An absent or
|
||||||
|
null API-key environment name means no lookup; a supplied name follows existing
|
||||||
|
normalization and naming rules. Absent/null concurrency means zero (unlimited);
|
||||||
|
supplied values must be nonnegative. Absent/null queue capacity selects the
|
||||||
|
existing default of 1024 for positive concurrency and no queue for unlimited
|
||||||
|
concurrency. Explicit queue capacity, including zero, requires positive
|
||||||
|
concurrency and must satisfy existing nonnegative/overflow checks. Null provider
|
||||||
|
maps mean no configured extra parameters; entries may contain JSON null.
|
||||||
|
Required endpoint failures, unknown fields, and domain errors apply to final
|
||||||
|
definitions, including unused ones. Registry construction consumes these final
|
||||||
|
normalized values; it does not replay registration or source-reservation checks.
|
||||||
|
|
||||||
|
Use ConfigKit's Resolve/Validate callbacks only on its effective post-layering,
|
||||||
|
post-inheritance typed values. These public lifecycle hooks implement the domain
|
||||||
|
handoff and record normalization; they are not hooks for inspecting earlier
|
||||||
|
contributions. Final presence lookup and resource-context lookup are sufficient
|
||||||
|
for interpretation. History/Explain/HistoricalPaths are operator inspection
|
||||||
|
facilities, not inputs to construction-time policy checks.
|
||||||
|
|
||||||
Use the existing prompt fields under each keyed version, without `id`/`version`.
|
Use the existing prompt fields under each keyed version, without `id`/`version`.
|
||||||
Use pointers for `content`, `content_file`, and optional clearable strings;
|
Use pointers for `content`, `content_file`, and optional clearable strings;
|
||||||
preserve existing input, cache-control, output-contract, and role rules.
|
preserve existing input, cache-control, output-contract, and role rules.
|
||||||
@@ -169,13 +223,15 @@ derived endpoint/key/defaults must not follow a child that changes backend.
|
|||||||
Provider map null entries are literal JSON null; empty mappings retain children.
|
Provider map null entries are literal JSON null; empty mappings retain children.
|
||||||
For backend-to-profile provider-map overlay, use a narrow JSON-value merge helper
|
For backend-to-profile provider-map overlay, use a narrow JSON-value merge helper
|
||||||
with the same recursive-map/value-replacement semantics; it is not a configuration
|
with the same recursive-map/value-replacement semantics; it is not a configuration
|
||||||
loader and must not interpret `extends` in backend runtime values.
|
loader. Both backend and profile configuration maps have already passed through
|
||||||
|
ConfigKit's reserved-key semantics; only request-level maps bypass that lifecycle.
|
||||||
|
|
||||||
Record any defaults/normalizations written into the typed configuration via
|
Record any defaults/normalizations written into the typed configuration via
|
||||||
ConfigKit Resolve, with dependencies on relevant configuration paths. Do not
|
ConfigKit Resolve, with dependencies on relevant configuration paths. Do not
|
||||||
project runtime collaborators or credentials into the configuration tree just to
|
project runtime collaborators or credentials into the configuration tree just to
|
||||||
report them. Inspection describes resolved configuration, while InspectProfile
|
report them. Inspection includes effective backend configuration. It describes
|
||||||
and preparation describe backend-completed execution settings. Make this boundary
|
resolved configuration, while InspectProfile and preparation describe
|
||||||
|
backend-completed execution settings. Make this boundary
|
||||||
explicit rather than inventing synthetic provenance for registry defaults.
|
explicit rather than inventing synthetic provenance for registry defaults.
|
||||||
|
|
||||||
Retain APIKeyRequired's direct-key workflow: true suppresses a backend-derived
|
Retain APIKeyRequired's direct-key workflow: true suppresses a backend-derived
|
||||||
@@ -237,8 +293,9 @@ ConfigKit SourceContext, mutable runtime values, or internal types. Delegate
|
|||||||
queries and redaction to the retained result. Nil Engine returns ErrInvalidConfig;
|
queries and redaction to the retained result. Nil Engine returns ErrInvalidConfig;
|
||||||
the zero inspection view has empty query results and writer operations return
|
the zero inspection view has empty query results and writer operations return
|
||||||
ErrInvalidConfig. Writer errors remain inspectable. Mark credential-shaped dynamic
|
ErrInvalidConfig. Writer errors remain inspectable. Mark credential-shaped dynamic
|
||||||
keys sensitive using Definition.Secret, reusing the existing catalog secret-key
|
keys sensitive using Definition.Secret; the existing secret-key vocabulary can
|
||||||
vocabulary; do not redact `api_key_env` names as credential values. This is not a
|
serve as a redaction predicate, not a source-rejection rule. Do not redact
|
||||||
|
`api_key_env` names as credential values. This is not a
|
||||||
promise that arbitrary prompt/provider content is safe to disclose.
|
promise that arbitrary prompt/provider content is safe to disclose.
|
||||||
|
|
||||||
Keep the runner independent of this view. Inspection calls perform no discovery,
|
Keep the runner independent of this view. Inspection calls perform no discovery,
|
||||||
@@ -253,18 +310,22 @@ and its focused tests. Leave engine assembly on the old path for this stage.
|
|||||||
|
|
||||||
1. Add ConfigKit v0.5.0; update go.sum and factual OSS notices for it and its
|
1. Add ConfigKit v0.5.0; update go.sum and factual OSS notices for it and its
|
||||||
selected transitive dependencies. Preserve project licenses and the Go floor.
|
selected transitive dependencies. Preserve project licenses and the Go floor.
|
||||||
2. Add the keyed DTOs and a private load entry point accepting ConfigKit Inputs
|
2. Add keyed backend/profile/prompt DTOs and a private load entry point accepting
|
||||||
and underlays. Call LoadLayered once, with no VersionRule or secret resolution
|
ConfigKit Inputs and underlays. Call LoadLayered once, with no VersionRule or
|
||||||
bindings for API credentials. Use callback-scoped Resolve/Validate correctly.
|
secret resolution bindings for API credentials. Use callback-scoped
|
||||||
3. Implement presence extraction and the field rules above. Validate supplied
|
Resolve/Validate correctly.
|
||||||
domain values through existing domain helpers; no final target requirement.
|
3. Implement effective presence extraction and the field rules above. Validate
|
||||||
|
final domain values through existing helpers, resolving backend references
|
||||||
|
against the final backend map; profiles have no final target requirement yet.
|
||||||
Record normalization/default mutations, not arbitrary DTO bookkeeping fields.
|
Record normalization/default mutations, not arbitrary DTO bookkeeping fields.
|
||||||
4. Preserve `*configkit.LoadError` through wrapping. Domain callback messages
|
4. Preserve `*configkit.LoadError` through wrapping. Domain callback messages
|
||||||
identify paths/problems without interpolating raw values or credentials.
|
identify paths/problems without interpolating raw values or credentials.
|
||||||
5. Add representative real-loader tests: keyed literal IDs, strict group conflict,
|
5. Add representative real-loader tests: keyed literal IDs, strict group conflict,
|
||||||
recursive cross-tier overlay, a shared base with explicit zero/null/false, an
|
recursive cross-tier overlay, a shared base with explicit zero/null/false, an
|
||||||
unused invalid effective definition, and a malformed lower source not hidden
|
unused invalid effective definition, and preservation of a ConfigKit load
|
||||||
by an overlay. Do not reproduce ConfigKit's parser/inheritance matrix.
|
error. Cover an invalid lower-layer domain value replaced by a valid final
|
||||||
|
value: construction succeeds. Do not reproduce ConfigKit's parser/inheritance
|
||||||
|
matrix or add preflight/source-policy tests.
|
||||||
|
|
||||||
Exit: focused tests and `go test ./...` pass; old engine behavior is not presented
|
Exit: focused tests and `go test ./...` pass; old engine behavior is not presented
|
||||||
as migrated. Internal inventory documents only the loader now actually present.
|
as migrated. Internal inventory documents only the loader now actually present.
|
||||||
@@ -297,8 +358,9 @@ existing execution tests still work through the old assembly until cutover.
|
|||||||
Scope: domain settings, target resolution, wire-presence propagation, profile
|
Scope: domain settings, target resolution, wire-presence propagation, profile
|
||||||
inspection. No new source discovery in execution packages.
|
inspection. No new source discovery in execution packages.
|
||||||
|
|
||||||
1. Add execution-owned presence/suppression state and construct indexed profiles
|
1. Build the immutable backend registry from the final loaded backend map. Add
|
||||||
from loader output plus the immutable backend registry. Apply registry-derived
|
execution-owned presence/suppression state and construct indexed profiles
|
||||||
|
from loader output plus that registry. Apply registry-derived
|
||||||
values after inheritance, using the field table above.
|
values after inheritance, using the field table above.
|
||||||
2. Replace scalar-zero/blank merge assumptions in target resolution. Configuration
|
2. Replace scalar-zero/blank merge assumptions in target resolution. Configuration
|
||||||
explicit zero reaches injected clients and the built-in request body; null does
|
explicit zero reaches injected clients and the built-in request body; null does
|
||||||
@@ -319,8 +381,8 @@ a compatibility promise. Update affected target/presence GoDoc with this change.
|
|||||||
|
|
||||||
## Stage 4 — Migrate The OpenRouter Catalog Assets
|
## Stage 4 — Migrate The OpenRouter Catalog Assets
|
||||||
|
|
||||||
Scope: `../promptkit-backend-openrouter` only. Resolve the catalog-validation open
|
Scope: `../promptkit-backend-openrouter` only. Catalog maintainers own source and
|
||||||
question before implementing its consumption strategy in Stage 6.
|
publishing checks here; PromptKit consumes its configuration through ConfigKit.
|
||||||
|
|
||||||
1. Read that repository's instructions; preserve unrelated work. Convert each
|
1. Read that repository's instructions; preserve unrelated work. Convert each
|
||||||
profile asset to `profiles: {literal-id: {settings...}}`, preserving inventory
|
profile asset to `profiles: {literal-id: {settings...}}`, preserving inventory
|
||||||
@@ -330,22 +392,29 @@ question before implementing its consumption strategy in Stage 6.
|
|||||||
2. Audit zero/empty values that previously meant unspecified. Remove those when
|
2. Audit zero/empty values that previously meant unspecified. Remove those when
|
||||||
omission was intended; retain intentional explicit values. Review any dynamic
|
omission was intended; retain intentional explicit values. Review any dynamic
|
||||||
provider `extends` keys rather than silently changing outbound payloads.
|
provider `extends` keys rather than silently changing outbound payloads.
|
||||||
3. Leave backend.json and its schema unchanged. Update catalog format notes and
|
3. Replace `catalog/backend.json` with `catalog/backend.yml` containing a
|
||||||
applicable tests to the keyed format, with a prominent incompatible-format
|
`backends: {openrouter: {settings...}}` mapping. Preserve endpoint, API-key
|
||||||
migration note. Model availability is not probed.
|
environment name, concurrency, queue, and extra-parameter values; remove the
|
||||||
|
duplicate id and old manifest schema_version. The file is an ordinary ConfigKit
|
||||||
|
input, not a separately decoded manifest. Update embedded assets, module path
|
||||||
|
and imports to `/v3`, tests, and catalog format/release documentation, with an
|
||||||
|
incompatible-format migration note. Keep FS/Root as the minimal export surface.
|
||||||
|
Catalog-local publishing checks stay in that repository. No provider probes.
|
||||||
4. Validate under its procedure and commit. If publication is authorized, publish
|
4. Validate under its procedure and commit. If publication is authorized, publish
|
||||||
the next unused `v2.YYYYMMDD.N`; otherwise report the exact commit awaiting
|
the next unused `v3.YYYYMMDD.N`; otherwise report the exact commit awaiting
|
||||||
publication. The date/revision is selected then, not guessed in this plan.
|
publication. The date/revision is selected then, not guessed in this plan.
|
||||||
|
|
||||||
Exit: one reviewed migrated catalog commit; existing immutable tags still serve
|
Exit: one reviewed migrated catalog commit; existing immutable tags still serve
|
||||||
old consumers. The profile-data change does not change the Go module path/API or
|
old consumers. The new major module path identifies the changed asset contract;
|
||||||
the JSON backend manifest. Warn old loaders not to consume the new assets.
|
old consumers retain the published `/v2` assets.
|
||||||
|
|
||||||
## Stage 5 — Migrate The Rakestrawhome Catalog Assets
|
## Stage 5 — Migrate The Rakestrawhome Catalog Assets
|
||||||
|
|
||||||
Scope: `../promptkit-backend-rakestrawhome` only. Apply the same keyed-format,
|
Scope: `../promptkit-backend-rakestrawhome` only. Apply the same keyed-format,
|
||||||
presence, notice, validation, and publication treatment as Stage 4 to its smaller
|
presence, notice, validation, and publication treatment as Stage 4 to its smaller
|
||||||
inventory. Preserve backend endpoint, credentials metadata, and capacity policy.
|
inventory, including the `/v3` transition and keyed `backends.rakestrawhome`
|
||||||
|
definition in `catalog/backend.yml`. Preserve backend endpoint, credentials
|
||||||
|
metadata, and capacity policy.
|
||||||
Do not couple its date/revision to OpenRouter's release.
|
Do not couple its date/revision to OpenRouter's release.
|
||||||
|
|
||||||
Exit: both compatible catalog versions are published and ordinarily resolvable
|
Exit: both compatible catalog versions are published and ordinarily resolvable
|
||||||
@@ -359,18 +428,22 @@ Scope: `internal/catalog`, maintained definitions, catalog integration tests,
|
|||||||
dependency pins/notices. Keep this separate from public API migration.
|
dependency pins/notices. Keep this separate from public API migration.
|
||||||
|
|
||||||
1. Pin the published compatible catalog versions and exact attribution commits.
|
1. Pin the published compatible catalog versions and exact attribution commits.
|
||||||
Keep strict backend.json loading/validation and registry construction.
|
Update imports to `/v3`. Replace manifest decoding with ConfigKit file Inputs.
|
||||||
2. Replace catalog profile repositories with ConfigKit file Inputs for the first
|
2. Supply backend and profile assets as ConfigKit Inputs in the first
|
||||||
underlay. Supply PromptKit-owned keyed Mapping definitions as the next group:
|
underlay. Supply PromptKit-owned keyed Mapping definitions as the next group:
|
||||||
standard extends the selected catalog's current maintained base; auto retains
|
standard extends the selected catalog's current maintained base; auto retains
|
||||||
its current direct model/backend definition. Preserve both literal names.
|
its current direct model/backend definition. Preserve both literal names.
|
||||||
3. Implement the selected catalog source-policy strategy from Open Questions.
|
3. Retire source-layout allowlists, catalog preflight, source ownership/reserved
|
||||||
Preserve reserved-name, ownership, connection-metadata, and secret checks;
|
prefix checks, connection-field prohibitions, and secret-key source rejection.
|
||||||
consumers may still override catalog profiles and their bases. Do not apply
|
The adapter selects known asset entry points and discovers configuration files;
|
||||||
catalog-only namespace restrictions to application sources.
|
ConfigKit acquires their contents. Domain validation sees only the final
|
||||||
|
assembled configuration. Consumers may overlay catalog backends, profiles,
|
||||||
|
and their bases through the same configuration model.
|
||||||
4. Test real imported assets offline with the new loader, maintained-name
|
4. Test real imported assets offline with the new loader, maintained-name
|
||||||
resolution, consumer override of a maintained base, and synthetic malformed
|
resolution, consumer override of a maintained base/backend, and rejection of
|
||||||
catalog fixtures for the source-policy risks. No upstream endpoint probes.
|
an invalid final backend. Test a replaced lower-layer domain error succeeds.
|
||||||
|
Do not independently validate catalog-only intermediate configurations, parse
|
||||||
|
raw assets in PromptKit tests, or audit origins to establish ownership.
|
||||||
|
|
||||||
Exit: catalog and owned definitions participate in the new keyed configuration
|
Exit: catalog and owned definitions participate in the new keyed configuration
|
||||||
model without a legacy profile parser on that path. Catalog integration tests
|
model without a legacy profile parser on that path. Catalog integration tests
|
||||||
@@ -384,8 +457,9 @@ adapters, and migration of their direct test setup.
|
|||||||
1. Introduce the Construction Surface exactly as specified above. Remove the
|
1. Introduce the Construction Surface exactly as specified above. Remove the
|
||||||
superseded source/profile options and convenience types rather than keeping
|
superseded source/profile options and convenience types rather than keeping
|
||||||
deprecated pass-through wrappers. Keep intentional runtime injection APIs.
|
deprecated pass-through wrappers. Keep intentional runtime injection APIs.
|
||||||
2. Assemble registry, combined configuration snapshot, renderer, validator,
|
2. Load the combined backend/profile/prompt configuration, construct its runtime
|
||||||
capacity manager, and runner. Return no Engine on construction failure.
|
registry and indexed snapshot, then assemble renderer, validator, capacity
|
||||||
|
manager, and runner. Return no Engine on construction failure.
|
||||||
Translate construction errors to ErrInvalidConfig while preserving LoadError
|
Translate construction errors to ErrInvalidConfig while preserving LoadError
|
||||||
via errors.As. Resource errors include semantic path and safe source context.
|
via errors.As. Resource errors include semantic path and safe source context.
|
||||||
3. Connect indexed prompt/profile lookups to preparation and inspection. Missing
|
3. Connect indexed prompt/profile lookups to preparation and inspection. Missing
|
||||||
@@ -393,7 +467,8 @@ adapters, and migration of their direct test setup.
|
|||||||
selection error. Old parse/load error categories need not be manufactured for
|
selection error. Old parse/load error categories need not be manufactured for
|
||||||
errors now detected at construction.
|
errors now detected at construction.
|
||||||
4. Move root test fixtures/setup and maintained example construction to ConfigKit
|
4. Move root test fixtures/setup and maintained example construction to ConfigKit
|
||||||
sources, keyed definitions, and ProfileSource so all consumers still compile.
|
sources, keyed definitions, ProfileSource, and BackendSource so all consumers
|
||||||
|
still compile. Update local-backend examples to choose their ID as a map key.
|
||||||
Update expected timing only for the deliberate eager-validation change. Keep
|
Update expected timing only for the deliberate eager-validation change. Keep
|
||||||
behavioral assertions for prompting, overrides, and errors.
|
behavioral assertions for prompting, overrides, and errors.
|
||||||
5. Add public tests for a minimal custom local backend and programmatic profile,
|
5. Add public tests for a minimal custom local backend and programmatic profile,
|
||||||
@@ -459,7 +534,8 @@ Scope: maintained examples and user-facing documentation.
|
|||||||
complete parser/inheritance contract.
|
complete parser/inheritance contract.
|
||||||
3. Update README and `docs/consumers/pkg-promptkit.md` with minimal local-backend,
|
3. Update README and `docs/consumers/pkg-promptkit.md` with minimal local-backend,
|
||||||
file/embedded source, programmatic Mapping/ProfileSource, explicit inspection,
|
file/embedded source, programmatic Mapping/ProfileSource, explicit inspection,
|
||||||
and engine-replacement workflows. Explain main versus ordered underlays.
|
and engine-replacement workflows. Explain main versus ordered underlays and
|
||||||
|
backend layering in place of registration-only restrictions.
|
||||||
4. Add concise old-to-new migration guidance in the consumer guide: removed API
|
4. Add concise old-to-new migration guidance in the consumer guide: removed API
|
||||||
options, exact IDs, `base_profile` to `extends`, zero/false/null, recursive maps,
|
options, exact IDs, `base_profile` to `extends`, zero/false/null, recursive maps,
|
||||||
no clear via `{}`, reserved `extends` runtime escape, failure timing, and the
|
no clear via `{}`, reserved `extends` runtime escape, failure timing, and the
|
||||||
@@ -478,14 +554,17 @@ internal architectural documentation.
|
|||||||
1. Delete lazy prompt/profile metadata prepasses, filesystem repositories,
|
1. Delete lazy prompt/profile metadata prepasses, filesystem repositories,
|
||||||
fallback-on-error overlays, custom base-chain resolver/depth cap, zero-sentinel
|
fallback-on-error overlays, custom base-chain resolver/depth cap, zero-sentinel
|
||||||
profile merging, and temporary stage adapters once no caller needs them.
|
profile merging, and temporary stage adapters once no caller needs them.
|
||||||
|
Remove the separate backend-manifest decoder, source-policy audits, and
|
||||||
|
pre-handoff backend registration validation. Keep final-value domain checks.
|
||||||
Retain narrow lookup interfaces only where they still simplify real consumers.
|
Retain narrow lookup interfaces only where they still simplify real consumers.
|
||||||
2. Retain useful filecatalog/schema utilities and JSON-value ownership/validation.
|
2. Retain useful filecatalog/schema utilities and JSON-value ownership/validation.
|
||||||
Remove direct yaml.v3 use and dependency if no remaining owner requires it;
|
Remove direct yaml.v3 use and dependency if no remaining owner requires it;
|
||||||
do not claim all YAML dependencies disappear when ConfigKit still uses YAML.
|
do not claim all YAML dependencies disappear when ConfigKit still uses YAML.
|
||||||
3. Move meaningful regressions from deleted package tests to their new owning
|
3. Move meaningful regressions from deleted package tests to their new owning
|
||||||
boundary. Retire tests only about old internals, repeated parser coverage, or
|
boundary. Retire tests about old internals, repeated parser coverage,
|
||||||
superseded semantics. Do not replace lost runtime protection with loader-only
|
source-policy enforcement, or superseded semantics. Do not replace lost runtime
|
||||||
tests. Keep private assembly checks separate from external facade tests.
|
protection with loader-only tests. Keep private assembly checks separate from
|
||||||
|
external facade tests.
|
||||||
4. Update `docs/internal/overview.md`, `docs/internal/sources.md`, relevant renderer
|
4. Update `docs/internal/overview.md`, `docs/internal/sources.md`, relevant renderer
|
||||||
and engine documents, and the implemented-structure paragraphs in architecture
|
and engine documents, and the implemented-structure paragraphs in architecture
|
||||||
policy. Describe the new package/dependency boundary without turning names or
|
policy. Describe the new package/dependency boundary without turning names or
|
||||||
@@ -523,45 +602,6 @@ Exit: the feature roadmap's end state is demonstrably implemented, with one
|
|||||||
configuration lifecycle, explicit operator inspection, no legacy loader, and
|
configuration lifecycle, explicit operator inspection, no legacy loader, and
|
||||||
no newly invented provider checks or human release gates.
|
no newly invented provider checks or human release gates.
|
||||||
|
|
||||||
## Open Questions
|
The catalog-validation placement question is resolved by the configuration-boundary
|
||||||
|
ADR. No design question remains open here. Catalog publication authority and
|
||||||
### Catalog Source-Policy Validation Versus Single-Pass Loading
|
ordinary module availability remain operational checkpoints for the catalog stages.
|
||||||
|
|
||||||
ConfigKit v0.5.0 performs typed callbacks only after effective overlay/inheritance;
|
|
||||||
it does not expose a raw-source policy callback. PromptKit currently checks each
|
|
||||||
catalog's resolved backend ownership and prohibited fields before consumer
|
|
||||||
overlays. Checking only the effective merged configuration would allow consumers
|
|
||||||
to mask a broken catalog contribution. Conversely, independently loading every
|
|
||||||
catalog and then loading the original sources again duplicates parsing and
|
|
||||||
inheritance work. Feeding the first load back as Mapping loses original source
|
|
||||||
provenance and changes when inheritance occurs. Neither workaround should be
|
|
||||||
silently described as the agreed single-pass design.
|
|
||||||
|
|
||||||
**Recommendation:** validate immutable catalog-only backend ownership and
|
|
||||||
source-policy rules in PromptKit's offline dependency contract tests, using real
|
|
||||||
ConfigKit and the selected released assets. At engine construction, retain
|
|
||||||
backend-manifest validation, strict source composition, effective domain
|
|
||||||
validation, and a history-based structural audit for reserved profile names,
|
|
||||||
forbidden connection fields, and prohibited secret-shaped keys contributed by
|
|
||||||
catalog sources (including masked paths). Use ConfigKit source IDs/history to
|
|
||||||
distinguish catalog contributions from permitted consumer overrides. Do not
|
|
||||||
parse Explanation YAML or rebuild an inheritance graph to recover historical
|
|
||||||
backend values. This keeps ordinary construction single-pass and treats pinned,
|
|
||||||
immutable dependency ownership as a tested distribution property. It changes the
|
|
||||||
location of part of existing catalog validation, so approval is needed before
|
|
||||||
Stage 6 rather than assuming it is merely an implementation detail.
|
|
||||||
|
|
||||||
**Viable alternative:** keep independent construction-time catalog preflight
|
|
||||||
loads through ConfigKit, followed by the combined load using original inputs.
|
|
||||||
This retains the current fail-closed runtime catalog checks and original
|
|
||||||
combined-load provenance, with simpler validation code. It deliberately relaxes
|
|
||||||
the acquire/parse-once efficiency objective for the bounded maintained catalogs
|
|
||||||
and adds repeated inheritance work; do not add a global cache to hide that cost.
|
|
||||||
If selected, document this narrow exception in the feature roadmap and benchmark
|
|
||||||
it. It need not affect single-pass loading of application sources.
|
|
||||||
|
|
||||||
An upstream raw-source policy hook could avoid the tradeoff, but it is a separate
|
|
||||||
ConfigKit feature request, not an assumed v0.5.0 capability or a reason to build
|
|
||||||
a replacement loader in PromptKit. All other decisions above are selected for
|
|
||||||
implementation; catalog publication permission is an operational checkpoint,
|
|
||||||
not an unresolved configuration-design choice.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user