370 lines
18 KiB
Markdown
370 lines
18 KiB
Markdown
# PromptKit concrete request validation
|
|
|
|
Status: accepted adoption and feature roadmap; implementation has not started.
|
|
Command placement, adapter composition, request construction, artifact syntax,
|
|
and initial presentation are settled. This document defines the target and
|
|
required work; the [implementation plan](implementation.md) sequences the work.
|
|
|
|
## Purpose
|
|
|
|
Adopt PromptKit v0.15.0 and expose its concrete request validation capability as
|
|
`app promptkit requirements validate PROMPT_ID`, alongside the delivered
|
|
`app promptkit requirements show PROMPT_ID` command.
|
|
|
|
The organizing principle is **CommandKit provides useful, consistent access to
|
|
capabilities owned elsewhere**. CommandKit owns vocabulary, registration,
|
|
selection, coordination, presentation, and invocation outcomes. PromptKit owns
|
|
what concrete request validation means. Applications supply their domain
|
|
mapping, defaults, artifacts, and runtime dependencies.
|
|
|
|
The command answers whether the constructed request passes native preparation
|
|
at the time of the invocation. It complements discovery without making
|
|
discovery a prerequisite for validation or validation a prerequisite for
|
|
application execution.
|
|
|
|
## Current baseline
|
|
|
|
The baseline is CommandKit commit `700f10d78ed0e410b0cc1d754fdd98415cd5817a`.
|
|
|
|
- The optional [ckprompt module](../../integrations/ckprompt/go.mod) requires
|
|
PromptKit v0.14.0, ConfigKit v0.7.1, and Go 1.26.0.
|
|
- Its [suite and engine adapters](../../integrations/ckprompt/adapters.go)
|
|
support independent prompt/profile catalogs, named definition inspection,
|
|
and requirements discovery. `FromEngine` supplies those callbacks using an
|
|
application-owned engine loader. There is no concrete validation callback.
|
|
- The [requirements command](../cli.md#promptkit-requirements) accepts a prompt
|
|
ID, configuration selection, typed suite selectors, version/profile/session
|
|
context, and repeatable variable assignments. It returns the native discovery
|
|
evidence as YAML. A partial inventory or missing variable is not itself an
|
|
invocation failure.
|
|
- `ConfigScope` separately exposes engine configuration inspection and
|
|
comparison through ckconfig. It does not install the PromptKit command family.
|
|
- The [composed consumer](../../integrations/ckprompt/examples/composed/main.go)
|
|
demonstrates discovery and application-owned configuration/engine loading.
|
|
It does not yet demonstrate construction or validation of a concrete request.
|
|
|
|
PromptKit v0.15.0 adds
|
|
[`Engine.ValidateRequest`](https://gitea.maximumdirect.net/eric/promptkit/src/commit/635674c066d0b432187f96e72b9c03d085443ac5/engine.go)
|
|
for an ordinary public `RunRequest`. Its
|
|
[consumer guide](https://gitea.maximumdirect.net/eric/promptkit/src/commit/635674c066d0b432187f96e72b9c03d085443ac5/docs/consumers/pkg-promptkit.md#validate-a-concrete-request)
|
|
and [release note](https://gitea.maximumdirect.net/eric/promptkit/src/commit/635674c066d0b432187f96e72b9c03d085443ac5/docs/releases/v0.15.0.md)
|
|
describe the addition. The reviewed release leaves the upstream minimum Go
|
|
version, module dependencies, and licensing material unchanged from v0.14.0.
|
|
|
|
## Targeted end state
|
|
|
|
### Command placement and meaning
|
|
|
|
The standard PromptKit family can expose both operations independently:
|
|
|
|
| Command | Operator purpose | Owning native capability |
|
|
| --- | --- | --- |
|
|
| `app promptkit requirements show PROMPT_ID` | Discover input and variable requirements for a prompt context. | `Engine.InspectRequirements` |
|
|
| `app promptkit requirements validate PROMPT_ID` | Check the actual constructed request, including supplied values and artifact bindings. | `Engine.ValidateRequest` |
|
|
|
|
The new handler delegates to concrete native validation. It does not infer
|
|
validity from the discovery report's `Complete`, inventory, or issues, and does
|
|
not independently interpret templates or decide which inputs are required.
|
|
|
|
Native validation shares `Prepare`'s request conversion and preparation path.
|
|
It may resolve prompt/profile resources, load artifacts and schema resources,
|
|
render messages and session context, and perform the applicable configuration
|
|
and credential checks. All supplied inputs follow native preparation behavior,
|
|
including inputs unused by the selected template branch. Errors are returned
|
|
as encountered rather than as an exhaustive inventory.
|
|
|
|
There is no model call or retained prepared snapshot. Success neither certifies
|
|
provider acceptance nor guarantees that a later execution will succeed. A later
|
|
run prepares independently. Applications needing execution tied to a checked
|
|
snapshot can use PromptKit's existing prepared-execution API in their own
|
|
workflow; that workflow is outside this feature.
|
|
|
|
### Operator inputs
|
|
|
|
Use the existing requirements command's common syntax for:
|
|
|
|
- One required prompt ID operand.
|
|
- `--config` and `--overlay`, with existing explicit-presence handling.
|
|
- Typed suite selectors.
|
|
- `--version`, `--profile`, and `--session-id`, forwarding their native
|
|
empty-string semantics.
|
|
- Repeatable `--var KEY=VALUE`, preserving the existing first-separator split,
|
|
exact keys and values, and last assignment for a duplicate key.
|
|
|
|
Keep singleton repetition and selector binding behavior consistent with the
|
|
current CLI contract. PromptKit owns semantic interpretation of the values.
|
|
The namespace identifies the library; configuration scope selection belongs
|
|
to the separate `config` family.
|
|
|
|
Add repeatable `--input NAME=PATH` for file-backed bindings, translated to native
|
|
`promptkit.File(PATH)` references without eagerly reading files. Split at the
|
|
first `=`, preserve exact names and paths, and use the last binding for a
|
|
duplicate name. Every occurrence is parsed; a later valid binding does not
|
|
erase an earlier malformed one.
|
|
|
|
| Invocation fragment | Result |
|
|
| --- | --- |
|
|
| `--input notes=notes.txt` | Bind `notes` to `promptkit.File("notes.txt")`. |
|
|
| `--input notes=dir/a=b.txt` | Preserve the path `dir/a=b.txt`. |
|
|
| `--input notes=` | Forward an empty file path to native validation. |
|
|
| `--input =notes.txt` | Forward the empty input name to native validation. |
|
|
| `--input notes=first.txt --input notes=second.txt` | Bind `notes` to `second.txt`. |
|
|
| `--input notes` | Usage error because the separator is missing. |
|
|
|
|
PromptKit owns semantic artifact validation and loading. CommandKit adds no
|
|
input-name whitelist, path restrictions, normalization, shell expansion, or
|
|
configuration-relative rebasing. Paths are preserved after shell processing.
|
|
|
|
Use `--format yaml` for the initial success report, with YAML as the default.
|
|
Application-specific settings continue to use typed application input and
|
|
callbacks. Applications can supply inline and domain-derived artifacts through
|
|
their builder; a standard inline-input flag is outside this delivery. The
|
|
command need not offer a built-in flag for every field in `RunRequest` to permit
|
|
applications to use those fields through their builder.
|
|
|
|
### Public integration and request construction
|
|
|
|
Add an independently optional concrete validation capability to `ckprompt.Suite`.
|
|
Installing validation alone must be useful; supplying discovery alone must
|
|
continue to install only discovery. Both operations belong to the same
|
|
`requirements` group when present. The existing installed-family ownership,
|
|
absent-suite behavior, and retained wiring errors apply.
|
|
|
|
Use a ckprompt-owned envelope containing configuration selection and the native
|
|
seed request populated from the standard command inputs:
|
|
|
|
```go
|
|
type ValidationRequest struct {
|
|
Selection ckconfig.Selection
|
|
Request promptkit.RunRequest
|
|
}
|
|
```
|
|
|
|
Add this optional callback field to `Suite[I, S]`:
|
|
|
|
```go
|
|
ValidateRequest func(
|
|
context.Context, ValidationRequest, I, S,
|
|
) (commandkit.Acquired[struct{}], error)
|
|
```
|
|
|
|
The acquisition container carries diagnostics; validation has no native result
|
|
value to invent. Custom callbacks remain available for application-owned runtime
|
|
arrangements.
|
|
|
|
Provide a suite-returning `WithRequestValidation` helper that takes a suite, the
|
|
existing engine-loader shape, and an optional typed builder:
|
|
|
|
```go
|
|
func WithRequestValidation[I, S any](
|
|
suite Suite[I, S],
|
|
load func(context.Context, ckconfig.Selection, I, S) (*promptkit.Engine, error),
|
|
build func(context.Context, ValidationRequest, I, S) (promptkit.RunRequest, error),
|
|
) Suite[I, S]
|
|
```
|
|
|
|
The helper attaches the engine-backed validation callback and retains construction
|
|
errors, including a nil loader, in the returned suite for installation to report.
|
|
Existing suite capabilities and attached issues are preserved. Narrowing the
|
|
capabilities afterward does not discard retained wiring errors. Returning a suite
|
|
gives these errors the same treatment as existing adapters.
|
|
|
|
For application-defined `loadEngine` and `buildRequest` callbacks, composition is:
|
|
|
|
```go
|
|
suite := ckprompt.FromEngine(loadEngine)
|
|
suite = ckprompt.WithRequestValidation(suite, loadEngine, buildRequest)
|
|
```
|
|
|
|
A validation-only consumer can start from an empty suite. Given its application
|
|
types `Input` and `State`, it can use the standard command-populated request
|
|
directly:
|
|
|
|
```go
|
|
suite := ckprompt.WithRequestValidation(
|
|
ckprompt.Suite[Input, State]{}, loadEngine, nil,
|
|
)
|
|
```
|
|
|
|
A nil builder passes the seed request unchanged to native validation. Standard
|
|
flags already supply useful prompt context, variables, and file bindings;
|
|
application mapping is optional. `FromEngine` alone continues to supply its
|
|
existing inspection callbacks, so validation remains an explicit wiring choice.
|
|
|
|
When present, the builder receives invocation context, the selection and seed
|
|
request, selected application input, and shared invocation state. It returns
|
|
the concrete native request. It can supply application artifacts, inline content,
|
|
execution/output-contract overrides, appended messages, credentials, or other
|
|
supported native settings. The adapter forwards that result without reapplying
|
|
or merging fields afterward.
|
|
|
|
Builders should start from the seed, preserve the selected prompt identity and
|
|
operator values, and add application defaults deliberately. Map defaults respect
|
|
key presence, including a supplied empty value. For example, within a builder:
|
|
|
|
```go
|
|
request := seed.Request
|
|
if request.Vars == nil {
|
|
request.Vars = make(map[string]string)
|
|
}
|
|
if _, supplied := request.Vars["audience"]; !supplied {
|
|
request.Vars["audience"] = "internal"
|
|
}
|
|
return request, nil
|
|
```
|
|
|
|
Here `seed` is the builder's `ValidationRequest`; `--var audience=` remains an
|
|
explicit empty value. Version, profile, and session fields retain their native
|
|
empty-string semantics, including equivalence between omitted and explicitly
|
|
empty scalar values. Configuration selection retains its existing presence
|
|
information. CommandKit documents these responsibilities without adding a second
|
|
native-field validation layer. Reusing a request builder between validation and
|
|
application execution is recommended consumer guidance.
|
|
|
|
### Invocation lifecycle and outcomes
|
|
|
|
Reuse the integration's current typed input preparation, selector application,
|
|
input checking, invocation state, configuration diagnostic adaptation, and
|
|
outcome/delivery machinery. Construction, installation, help, and version must
|
|
leave acquisition and request-building callbacks uninvoked, under the existing
|
|
[architecture policy](../policy/architecture.md).
|
|
|
|
For the bundled adapter, use this order:
|
|
|
|
1. Complete CLI preflight and application input checks.
|
|
2. Create shared invocation state.
|
|
3. Invoke the builder, if supplied; otherwise use the seed request unchanged.
|
|
4. Load the engine using the selected configuration, application input, and state.
|
|
5. Invoke native validation with the concrete request.
|
|
6. Deliver diagnostics and the success report through the established paths.
|
|
|
|
Both builder and loader receive the same invocation state and context.
|
|
Applications can explicitly share configuration acquisition through that state.
|
|
A builder failure prevents engine loading. Check cancellation between stages,
|
|
preserve diagnostics already acquired, and leave later stages uninvoked after
|
|
failure. Preserve supported native error identity and configuration diagnostics,
|
|
including failures during engine loading.
|
|
|
|
Use the existing classification model: malformed CLI syntax and missing
|
|
operands are usage failures. Application input-check failures retain their
|
|
existing handling. Builder, engine-loader, and native-validation failures are
|
|
operational failures with supported error identity preserved. Returned provider
|
|
errors do not carry arbitrary usage or domain outcome classifications;
|
|
application-owned handlers can return their own outcomes. Preserve
|
|
native cancellation error categories; do not add a promise that every native
|
|
failure matches `ctx.Err()`.
|
|
|
|
Successful native validation produces the selected success presentation only
|
|
after it succeeds. Diagnostics and output failures follow the established
|
|
delivery contract. The presentation reports the validation outcome without
|
|
dumping the request, artifact content, credential values, or rendered messages.
|
|
|
|
### Initial success presentation
|
|
|
|
Emit one small YAML report, defaulting to YAML and accepting explicit
|
|
`--format yaml` as the only format for this delivery:
|
|
|
|
```yaml
|
|
prompt_id: briefing
|
|
valid: true
|
|
```
|
|
|
|
The ID identifies the command's requested prompt. `valid` means that validation
|
|
of the concrete request returned nil at this invocation; with the bundled
|
|
adapter, this is the result of native preparation. Builder guidance preserves
|
|
the selected prompt identity so the confirmation describes the operator's
|
|
selection. CommandKit adds no independent identity-validation layer.
|
|
|
|
Native validation supplies neither resolved version/profile metadata nor a
|
|
prepared snapshot. The report therefore contains no such claims or discovery
|
|
inventories. Failures use the existing diagnostic/error outcome path. Output
|
|
delivery is part of invocation success. This initial presentation provides an
|
|
explicit confirmation for operators and automation; additional formats can
|
|
follow concrete needs.
|
|
|
|
### Package and dependency ownership
|
|
|
|
All new provider contracts, request adaptation, standard handlers, and
|
|
presentation belong in `integrations/ckprompt`. Core continues to own generic
|
|
declarations, bindings, dispatch, and outcomes. ckconfig remains responsible
|
|
for its configuration adaptation; ckprompt can reuse it where appropriate.
|
|
|
|
Adopt the released PromptKit v0.15.0 module. Preserve the current Go minimum
|
|
and dependency direction: ckprompt may depend on ckconfig; ckconfig and core
|
|
do not acquire a PromptKit dependency. Use public upstream APIs and released
|
|
module versions, without sibling-checkout requirements in committed manifests.
|
|
|
|
## Work needed from the baseline
|
|
|
|
### Dependency adoption
|
|
|
|
Update ckprompt's PromptKit requirement and checksums to v0.15.0. Review the
|
|
resulting selected module graph, and update the PromptKit attribution entry's
|
|
selected version and source/notice links to release commit
|
|
`635674c066d0b432187f96e72b9c03d085443ac5`. Update other attribution entries only
|
|
where the selected graph or incorporated material actually changes.
|
|
|
|
### Integration API and native adapter
|
|
|
|
Add `ValidationRequest`, the optional suite callback, and the suite-returning
|
|
`WithRequestValidation` helper. Reuse existing engine-loading diagnostics and
|
|
supported error handling.
|
|
Support concrete request construction from typed application input and standard
|
|
CLI values, without copying PromptKit's preparation logic. Account for builder
|
|
failure and invalid loader wiring using the established integration conventions;
|
|
a nil builder uses the seed unchanged.
|
|
|
|
Keep current discovery and configuration adapters available independently.
|
|
`FromEngine` keeps its current capabilities. Validation is explicitly enabled
|
|
through the helper or a custom suite callback, with an application builder only
|
|
when additional mapping or defaults are needed.
|
|
|
|
### Command assembly, bindings, and presentation
|
|
|
|
Extend `ckprompt.Command` to assemble the requirements group from its supplied
|
|
show and validate capabilities. Add the validate handler, file-binding syntax,
|
|
and YAML success report. Share common binding/report mechanics where
|
|
that simplifies the code, preserving the delivered discovery contract.
|
|
|
|
### Maintained consumer and documentation
|
|
|
|
Extend the composed consumer with a synthetic concrete request builder and
|
|
offline validation examples for a successful request and a missing required
|
|
binding. Demonstrate the existing typed domain selectors alongside the new
|
|
standard bindings. The example should make the different questions answered
|
|
by show and validate clear without requiring a model service or real credential.
|
|
Document the nil-builder path and a builder that preserves supplied map entries
|
|
while adding defaults.
|
|
|
|
When implemented, update Go declarations/GoDoc, the CLI reference, consumer
|
|
guide, and affected orientation/internal descriptions under their canonical
|
|
owners. Describe native resource work and validation limits accurately, so
|
|
statements about metadata inspection do not accidentally claim that concrete
|
|
validation performs no rendering, artifact loading, or credential checks.
|
|
|
|
This capability fits the accepted optional-family and owning-library boundaries.
|
|
No new ADR or revision to accepted ADRs is needed. The selected API and CLI
|
|
details belong in their canonical documentation when implemented.
|
|
|
|
### Completion evidence for implementation
|
|
|
|
Use proportionate public-boundary evidence for independent capability
|
|
availability, help without acquisition, standard/typed input mapping, fresh
|
|
invocation state, nil-builder forwarding, builder default precedence, retained
|
|
wiring errors, builder-before-loader behavior, native validation error identity,
|
|
and diagnostic/output delivery. Cover builder and loader failures and cancellation
|
|
between stages. Use a real PromptKit engine for representative
|
|
successful validation and a missing binding, with a model-call double that
|
|
detects accidental execution. Protect continued successful discovery of a
|
|
partial inventory; do not turn it into a validation failure.
|
|
|
|
Check semantic output rather than YAML key ordering or native error wording.
|
|
Avoid duplicating PromptKit's complete preparation test suite. Validate the
|
|
owning integration and affected composed consumer; check isolated module
|
|
resolution and dependency boundaries for the upgrade, using the established
|
|
workspace and disposable-module practices in the
|
|
[developer guide](../development.md). Implementation evidence must not rely
|
|
solely on a workspace that silently substitutes a sibling PromptKit checkout.
|
|
|
|
The decisions needed for an implementation plan are settled.
|