169 lines
8.9 KiB
Markdown
169 lines
8.9 KiB
Markdown
# Request Preflight Validation
|
|
|
|
Status: accepted; implementation pending.
|
|
|
|
## Purpose
|
|
|
|
Provide an explicit success/error operation for consumers that want to check an
|
|
actual prompt request without generating a model response or receiving a
|
|
prepared snapshot.
|
|
|
|
The check applies to concrete variable values and input bindings for one
|
|
invocation. It does not certify that an application's configured bindings cover
|
|
every possible request or template branch.
|
|
|
|
Scriptorium motivates this addition: applications invoke it as a subprocess and
|
|
could use a `validate` command to fail early when their supplied variables,
|
|
inputs, or other request settings cannot pass preparation. PromptKit owns the
|
|
reusable request operation; Scriptorium owns command syntax, diagnostics,
|
|
process exit statuses, and any application-specific interpretation.
|
|
|
|
## Current Baseline
|
|
|
|
`Engine.InspectRequirements` discovers recognizable input and caller-variable
|
|
dependencies without loading artifacts or rendering messages. Its `Complete`
|
|
flag describes discovery coverage, not whether supplied dependencies satisfy a
|
|
request. It is useful for authoring and planning, but is not actual preflight.
|
|
|
|
`Engine.Prepare` already performs preflight through request conversion and the
|
|
shared internal preparation pipeline. It resolves the prompt, profile, effective
|
|
settings, and output contract; loads input artifacts and applicable schema
|
|
resources; and renders messages and the session ID without calling an LLM.
|
|
The facade then converts the internal prepared value into a caller-owned
|
|
`PreparedRun`. Consumers can discard that result today, but the API does not
|
|
directly express a success/error-only operation.
|
|
|
|
See the [consumer inspection and preparation guide](../consumers/pkg-promptkit.md#inspect-requirements-before-preparation),
|
|
[existing preparation GoDoc](../../engine.go), and
|
|
[internal preparation flow](../internal/runner.md#shared-preparation-pipeline).
|
|
|
|
## Target Public API
|
|
|
|
Add a separate method on the existing engine:
|
|
|
|
```go
|
|
func (e *Engine) ValidateRequest(ctx context.Context, req RunRequest) error
|
|
```
|
|
|
|
`ValidateRequest` names the object being checked and distinguishes this operation
|
|
from generated-output validation. `validate` remains the recommended downstream
|
|
CLI command name; preflight describes the workflow, without implying provider
|
|
or capacity readiness checks.
|
|
|
|
Use the complete existing `RunRequest`, including input bindings, caller
|
|
variables, profile selection, execution overrides, session settings, output
|
|
contract overrides, and appended messages. Apply the same request conversion
|
|
and preparation rules as `Prepare`; validation is not a name-only check or an
|
|
analysis of declared requirements.
|
|
|
|
A nil error means **the supplied request passed preparation at the time of the
|
|
check**. A failure returns the error encountered through the existing
|
|
preparation path, with the same public error categories and applicable error
|
|
identities. A nil engine follows `Prepare`'s `ErrInvalidConfig` convention.
|
|
Context handling follows preparation rather than introducing a stronger
|
|
cancellation guarantee. The result does not aggregate all missing requirements
|
|
or return a prepared value, execution handle, or model output.
|
|
|
|
Keep `Prepare` unchanged. A separate method avoids a mode flag that changes the
|
|
meaning of its returned snapshot. The intended distinction is:
|
|
|
|
- `InspectRequirements`: discover what a prompt may require for a supplied
|
|
context, including partial discovery where appropriate.
|
|
- `ValidateRequest`: determine whether the actual supplied request passes
|
|
preparation.
|
|
- `Prepare`: perform preparation and return its snapshot.
|
|
- `PrepareExecution`: prepare an owned snapshot that can later be executed.
|
|
- `Run`: prepare and execute the request.
|
|
|
|
## Meaning And Limits
|
|
|
|
Validation exercises actual preparation, including loading inputs and rendering
|
|
the branches selected by supplied values. It applies existing rules to missing
|
|
bindings and variables rather than adding stricter required-field rules,
|
|
rejecting additional caller keys, or restricting supported templates.
|
|
|
|
For example, consider a message containing
|
|
`{{if eq .mode "detailed"}}{{input "details"}}{{end}}`, where `details` is not
|
|
declared required. A request with `mode=brief` can prepare without that input;
|
|
one with `mode=detailed` needs it. Declaring the input required makes it
|
|
necessary regardless of the selected branch. Similarly, an evaluated
|
|
`{{.audience}}` fails when the key is absent, but supplying an empty string does
|
|
not itself fail preparation. Optional lookups such as `{{index . "audience"}}`
|
|
retain their existing semantics. These examples illustrate preparation parity,
|
|
not new required-field rules; see the [input and template formats](../formats.md#inputs)
|
|
and [requirement classifications](../../requirements.go).
|
|
|
|
No LLM request is made. This is not a promise of zero I/O: artifact and schema
|
|
loaders still perform their existing resource work, including caller-supplied
|
|
loader behavior. The current preparation path loads every supplied input, even
|
|
if the selected template branch does not use it. Avoiding inference makes the
|
|
operation useful for fail-fast workflows, but large inputs or resource
|
|
processing can still cost time and memory. No fixed latency or allocation
|
|
guarantee is proposed.
|
|
|
|
Success does not establish provider acceptance, context-window fit, generated
|
|
output validity, or application-domain correctness. It also does not reserve
|
|
execution capacity or retain a snapshot for a subsequent invocation. Later
|
|
requests can differ, and referenced resources can change. Consumers that need
|
|
execution tied to the checked snapshot within one process and engine should use
|
|
`PrepareExecution`. Its [opaque handle](../../prepared_execution.go) cannot
|
|
connect separate subprocess invocations.
|
|
|
|
This is request-scoped validation using an already constructed engine. It does
|
|
not expand configuration ownership beyond the final handoff described by
|
|
[ADR 0001](../adr/0001-configuration-boundary.md), or introduce eager validation
|
|
of all configured prompts and resources.
|
|
|
|
## Downstream CLI Guidance
|
|
|
|
Scriptorium's proposed `validate` and existing `run` commands should share
|
|
request construction: argument interpretation, defaults, profile selection,
|
|
and overrides must describe the same request for equivalent caller inputs.
|
|
This allows PromptKit's preparation parity to carry through the CLI boundary.
|
|
Scriptorium owns exit statuses and diagnostic presentation.
|
|
|
|
A `scriptorium validate` call followed by `scriptorium run` performs two
|
|
independent preparations; the first does not retain an executable snapshot for
|
|
the second. When assessing CLI latency, measure the complete subprocess call,
|
|
including process startup and engine construction, as well as preparation.
|
|
Avoiding the public prepared snapshot does not eliminate the other preparation
|
|
work. These are downstream integration recommendations, not Scriptorium changes
|
|
included in this unit of work.
|
|
|
|
## Work Needed
|
|
|
|
- Add the public error-only method through the existing facade and internal
|
|
preparation path. Reuse request conversion, preparation, and error mapping
|
|
rather than implementing a second validation engine or an inspection-based
|
|
approximation.
|
|
- Discard the internal prepared result without converting it into a public
|
|
snapshot. The existing internal prepared value may still be constructed;
|
|
removing all preparation allocations is not required for this addition.
|
|
Share small facade plumbing where helpful without a broad refactor.
|
|
- Preserve preparation's existing context, credential, resource, and execution
|
|
separation behavior. No model generation, output-repair loop, or capacity
|
|
admission is needed for the new operation.
|
|
- Add focused external-package tests for successful preparation and
|
|
representative missing-variable/input, resource, selection, and invalid-request
|
|
failures. Use existing fixtures where suitable to verify parity with
|
|
`Prepare`, including a branch-sensitive example and the nil-engine boundary.
|
|
Check public error identities rather than exact messages, and confirm that
|
|
the injected model client is not called. Avoid duplicating the full
|
|
preparation test suite.
|
|
- Document the method in GoDoc and add a short consumer example distinguishing
|
|
validation from requirement discovery and prepared execution. Update the
|
|
internal runner description where needed when implementation lands, and
|
|
record the optional API addition in its eventual release notes.
|
|
|
|
## Completion And Scope
|
|
|
|
The feature is complete when consumers can submit an ordinary `RunRequest` to
|
|
`Engine.ValidateRequest` and obtain preparation success or its existing failure
|
|
without a model call or public prepared snapshot, with focused tests and
|
|
canonical documentation establishing that behavior.
|
|
|
|
This unit of work does not include changes to Scriptorium, CLI commands or exit
|
|
codes, aggregated diagnostics, presence-only validation modes, provider probes,
|
|
domain-aware validation, or new execution guarantees. It introduces no changes
|
|
to prompt/profile formats or existing preparation and execution semantics.
|