From 60784e7875191bf25d2a9b03bf6a35f3ad5f2c88 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Mon, 12 Oct 2026 17:47:04 +0000 Subject: [PATCH] Document request validation workflow --- docs/consumers/pkg-promptkit.md | 42 +++++++++++++++++++++++++++-- docs/internal/overview.md | 2 +- docs/internal/runner.md | 6 +++++ docs/roadmap/implementation.md | 2 ++ engine.go | 11 +++++--- examples/go-library/prepare/main.go | 8 ++++-- 6 files changed, 62 insertions(+), 9 deletions(-) diff --git a/docs/consumers/pkg-promptkit.md b/docs/consumers/pkg-promptkit.md index 50fa1bd..bbb9145 100644 --- a/docs/consumers/pkg-promptkit.md +++ b/docs/consumers/pkg-promptkit.md @@ -284,6 +284,41 @@ conditional entries. Do not treat an empty partial inventory as proof that no input bindings are needed. See the method's [GoDoc](../../requirements.go) for the exact classifications, supported syntax, ownership, and error contract. +## Validate A Concrete Request + +Use [`Engine.ValidateRequest`](../../engine.go) when the application has a +complete `RunRequest` and needs to know whether that concrete invocation passes +preparation: + +```go +request := promptkit.RunRequest{ + PromptID: "meeting.summary", + Vars: map[string]string{"audience": "project leads"}, + Inputs: map[string]promptkit.ArtifactRef{ + "note": promptkit.Inline("Synthetic meeting notes"), + }, +} +if err := engine.ValidateRequest(ctx, request); err != nil { + return err +} +``` + +Unlike `InspectRequirements`, this checks supplied values, the selected template +branches, and request bindings through the existing preparation path. It checks +only this invocation, does not aggregate errors, and loads every supplied input +according to ordinary preparation behavior, even if a branch does not use it. +It makes no model call and returns no prepared snapshot, but artifact and schema +resource I/O and its time and memory costs remain. Success does not certify +provider acceptance or later execution success. See the method's GoDoc for its +exact error and context behavior. + +Scriptorium can map the returned error to its own diagnostics and exit status. +Its `validate` and `run` commands should construct equivalent requests for +equivalent caller inputs so their preparation behavior agrees. Separate +subprocess calls prepare independently; an opaque `PrepareExecution` handle +cannot be transferred from `validate` to `run`. Use `PrepareExecution` when one +process and engine must execute the exact prepared snapshot. + ## Prepare Without Model Execution [`Engine.Prepare`](../../engine.go) resolves the selected prompt and profile, @@ -304,8 +339,11 @@ prepared, err := engine.Prepare(ctx, promptkit.RunRequest{ The maintained [offline preparation example](../../examples/go-library/prepare/main.go) shows a complete runnable setup with a prompt file, in-memory profile, and -inline input. Exact request requirements and prepared-result fields belong to -the [`RunRequest` and `PreparedRun` GoDoc](../../types.go). +inline input. It demonstrates validation and preparation with the same request +to make the two operations concrete; this performs preparation twice and is +illustrative, not a requirement to validate before `Prepare` or `Run`. Exact +request requirements and prepared-result fields belong to the +[`RunRequest` and `PreparedRun` GoDoc](../../types.go). ## Prepare Now And Execute The Same Snapshot Later diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 0991714..0d4bd20 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -11,7 +11,7 @@ contributor workflow and validation. | Component | Implemented responsibility | References | | --- | --- | --- | -| Root `promptkit` package | Provides the supported engine facade, ConfigKit source helpers, profile and backend mapping conveniences, injection options, public requests and results, prompt/profile/requirement inspection and identity listing, observation values, opaque prepared-execution handles, value conversion, redacted formatting, and typed capacity and generation error mapping. | [Package GoDoc](../../doc.go), [observations](../../observations.go), [prepared execution](../../prepared_execution.go), [backend API](../../backends.go), [engine facade](../../engine.go), [identity listing](../../listing.go), [requirement facade](../../requirements.go) | +| Root `promptkit` package | Provides the supported engine facade, ConfigKit source helpers, profile and backend mapping conveniences, injection options, public requests and results, prompt/profile/requirement inspection and identity listing, concrete-request validation, observation values, opaque prepared-execution handles, value conversion, redacted formatting, and typed capacity and generation error mapping. | [Package GoDoc](../../doc.go), [observations](../../observations.go), [prepared execution](../../prepared_execution.go), [backend API](../../backends.go), [engine facade](../../engine.go), [identity listing](../../listing.go), [requirement facade](../../requirements.go) | | `examples/go-library/prepare` | Demonstrates offline preparation and explicit configuration inspection with a prompt file, programmatic profile, and inline input. It is not a public library package. | [Example program](../../examples/go-library/prepare/main.go) | | `examples/go-library/run` | Demonstrates an offline downstream consumer using a prompt file, programmatic profile, inline input, an injected deterministic model client, and `Run`. It is not a public library package. | [Example program](../../examples/go-library/run/main.go) | | `examples/go-library/observe` | Demonstrates offline built-in HTTP retry and synchronous metadata observation across structured proposal and assessment runs using embedded sources, two profiles on one finite backend, and an application decision. It is not a public library package. | [Example program](../../examples/go-library/observe/main.go) | diff --git a/docs/internal/runner.md b/docs/internal/runner.md index ee4532d..b540527 100644 --- a/docs/internal/runner.md +++ b/docs/internal/runner.md @@ -111,6 +111,12 @@ into its private payload, while deep-copying mutable provider extras and creating an independent details snapshot. Claim completion or discard clears the execution payload without removing the details snapshot. +The root facade's `Engine.ValidateRequest` uses the same complete preparation +path as `Prepare` and discards the resulting internal prepared value without +converting it into a public snapshot. It does not add a runner operation or +validator component; request conversion and public error mapping remain at the +facade boundary. + Pointer-based numeric overrides preserve an explicit zero. Invalid negative or out-of-range values fail as invalid requests. Endpoint overrides do not change the selected backend identity. Non-empty extra-parameter maps replace whole diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index a7d8dce..5e05e95 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -187,6 +187,8 @@ example are coherent; existing preparation and execution workflows remain available; and the integrated checks pass. Report actual check results and stage commits. The completed roadmap can be retired during later release preparation. +**Completed: 2026-10-12.** + ## Open Questions None. The finalized roadmap resolves the public name, request shape, result, diff --git a/engine.go b/engine.go index 274765d..7f8e9ef 100644 --- a/engine.go +++ b/engine.go @@ -355,13 +355,16 @@ func (e *Engine) Prepare(ctx context.Context, req RunRequest) (*PreparedRun, err // ValidateRequest reports whether req passes the same preparation path used by // [Engine.Prepare] at the time of this call. A nil error means this concrete -// request passed preparation. The method returns no prepared snapshot or -// executable handle. It does not call an LLM, but preparation may still perform -// resource I/O, including loading supplied inputs and schemas. +// request passed preparation. It checks only this invocation and returns errors +// as encountered rather than aggregating them. All supplied inputs follow the +// same loading behavior as [Engine.Prepare], including inputs unused by the +// selected template branch. The method does not call an LLM or retain a +// prepared snapshot or executable handle, but preparation may still perform +// resource I/O and incur its associated time and memory costs. // // Its errors and context handling follow [Engine.Prepare], including an error // matching ErrInvalidConfig when the Engine is nil. Success does not guarantee -// that a provider will accept a later request. Use [Engine.PrepareExecution] +// provider acceptance or later execution success. Use [Engine.PrepareExecution] // when execution must use the snapshot produced by preparation. func (e *Engine) ValidateRequest(ctx context.Context, req RunRequest) error { _, err := e.prepareRequest(ctx, req) diff --git a/examples/go-library/prepare/main.go b/examples/go-library/prepare/main.go index 2129c70..d596c46 100644 --- a/examples/go-library/prepare/main.go +++ b/examples/go-library/prepare/main.go @@ -48,12 +48,16 @@ func main() { exit(fmt.Errorf("required note input was not discovered before preparation")) } - prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{ + request := promptkit.RunRequest{ PromptID: "example.prepare", Inputs: map[string]promptkit.ArtifactRef{ "note": promptkit.Inline("Ada finished the migration review."), }, - }) + } + if err := engine.ValidateRequest(context.Background(), request); err != nil { + exit(err) + } + prepared, err := engine.Prepare(context.Background(), request) if err != nil { exit(err) }