Simplify requirement inspection plan

This commit is contained in:
2026-10-08 19:58:57 +00:00
parent e459c7d54b
commit a6e0ffea8f
2 changed files with 518 additions and 712 deletions

View File

@@ -1,273 +1,227 @@
# Effective Prompt Requirement Inspection
Status: Implementation planned; the feature is not implemented. The
[implementation plan](implementation.md) owns the ordered migration steps and
implements the agreed analysis scope and inventory below. This document owns
the target end state and migration scope.
[implementation plan](implementation.md) owns the ordered implementation steps.
This document owns the purpose, scope, and target end state.
## Purpose
Let consumers discover a selected prompt's caller requirements before its input
artifacts exist. Scriptorium can expose that information to operators and to
Narratio, which can compare its planned bindings with Promptkit's exact input
names before undertaking expensive pipeline work.
Let consumers enumerate a selected prompt's inputs and caller variables before
its input artifacts exist, with each name classified as required, conditional,
or optional for the supplied context. Scriptorium can present that inventory
to operators and Narratio can compare planned bindings with exact input names
before undertaking expensive pipeline work.
The originating request is `docs/roadmap/scriptorium-feature-request.md`.
The capability is application-neutral: Promptkit describes prompt requirements;
consumers interpret them for their own configuration, presentation, and workflow.
The originating request is [Scriptorium's feature request](scriptorium-feature-request.md).
Promptkit supplies application-neutral inspection; consumers own presentation,
binding checks, and their own workflows.
## Current Baseline
At review baseline `b595dca`:
- [InspectPrompt](../consumers/pkg-promptkit.md#inspect-a-prompt-before-preparation)
selects a captured prompt and reports declared inputs and output metadata.
It does not analyze templates or resolve the execution profile.
selects a captured prompt and reports declared inputs and output metadata,
without analyzing templates or resolving an execution profile.
- [InspectProfile](../consumers/pkg-promptkit.md#inspect-a-profile-before-prompt-work)
reports one captured profile's effective target separately.
reports a captured profile's effective target separately.
- [Prepare](../consumers/pkg-promptkit.md#prepare-without-model-execution)
selects the execution context, checks target requirements, loads artifacts
and applicable schemas, and renders messages. It needs actual input data.
- The configuration adapter captures final effective definitions, message
contents, and compiled message/session templates during engine construction.
Runtime rendering uses Go templates, string-valued caller variables, and the
`input` helper. Declared required inputs are checked independently of template
branches; active helper calls also require their named inputs.
- Declared input metadata currently uses string fields for content type and
description. The new result needs to identify a declaration and distinguish
available metadata from absent metadata, including effective presence where
necessary; current empty strings alone do not establish source-field presence.
selects an execution context, loads artifacts and applicable schemas, and
renders messages. It needs actual input data.
- Engine construction captures final definitions and compiled message/session
templates. Rendering uses Go templates, string-valued caller variables, and
the `input` helper. Required input declarations are checked independently of
branches; an executed helper also needs its named input.
- Declared content types and descriptions currently use string fields. The
new inspection needs declaration information and effective metadata presence,
including the difference between an absent field and an explicitly empty one.
The [format reference](../formats.md#messages-and-templates),
[internal source document](../internal/sources.md), and existing GoDoc own the
implemented semantics. No existing operation provides artifact-free,
context-sensitive requirement discovery.
The [format reference](../formats.md#messages-and-templates), existing GoDoc,
and [internal source document](../internal/sources.md) own current behavior.
## Target Public Operation
Add a separate read-only engine operation, planned as
`Engine.InspectRequirements`, with a dedicated request and result. Preserve
`InspectPrompt`, `InspectProfile`, preparation, and execution contracts.
Add `Engine.InspectRequirements` with dedicated public request/result values.
Preserve `InspectPrompt`, `InspectProfile`, preparation, and execution.
The request supplies a prompt ID, optional version, optional profile selector,
supplied template variables, and an optional direct session ID. It needs no
artifact references or contents, output path, API key, or execution settings
unrelated to discovery.
The request supplies a prompt ID, optional version and profile selectors,
caller variables, and an optional direct session ID. It needs no artifact
references or contents, output path, or credentials.
Selection follows equivalent execution semantics: exact identities, omitted
version ambiguity, request profile or prompt default, and direct session-ID
normalization and bypass. Return selected prompt ID/version and effective
profile ID. Profile selection establishes identity, not generation readiness;
profiles that depend on later execution overrides need not be completed here.
Use execution's selection semantics: exact identities, omitted-version
ambiguity, request profile or prompt default, and normalized direct session-ID
bypass. Report the selected prompt ID/version and effective profile ID.
Selecting a profile establishes identity, not generation readiness; partial
profiles remain inspectable.
Use the configured engine's captured definitions. Source discovery and layering
remain consumer choices. Results describe that captured context, not a promise
about a later engine or later execution with changed variables.
Use the configured engine's captured definitions. Source selection remains a
consumer choice. Results describe that captured context, not a later engine or
execution with different variables.
## Result And Requirement Meanings
## Result And Classification
Expose public Go values with documented classifications and predictable ordering.
Exact symbol and field spelling belongs in the implementation plan
and GoDoc. No Promptkit JSON wire schema is part of this feature.
Return an inventory of inputs and a separate inventory of caller variables.
Each entry has one of three requirement classifications:
The result contains:
- **Required:** A declaration or recognized definite access establishes that
the caller must supply it.
- **Conditional:** Its necessity remains unresolved, including references on
paths whose applicability the supported analysis cannot determine.
- **Optional:** It is known not to be required, including recognizable references
used only on known inactive paths and nonrequired declarations or lookups.
- Selected prompt and profile identities.
- Known input names, preserving execution identity, with required, optional,
or conditional classification for the supplied context.
- Declaration information, descriptions, and content-type metadata where
available. A template-discovered undeclared input must not look like a
declared input with known metadata. Report existing media-type metadata,
not an invented input schema or inferred format constraint.
- An inactive-use explanation for statically identifiable undeclared inputs
referenced only on known inactive paths. These are optional inventory entries,
not bindings the current context needs. Keep this explanation separate from
declared descriptions.
- Variable requirements separately from artifact inputs, with requirement
classification and whether supplied values satisfy the known requirement.
Report presence and actual supported semantics, not the supplied values.
- A discovery-completeness indicator and structured uncertainty reasons, with
safe explanations and relevant identifiers where available.
A required declaration stays required even in an inactive branch. A definite
helper use promotes an optional input declaration to required. Aggregate repeated
occurrences by exact name: required takes precedence over conditional, which
takes precedence over optional. Conservative conditional classification is
acceptable where analysis cannot establish necessity; inspection need not prove
equivalence between alternative execution paths.
Required means the caller must supply the input for this context. A declared
required input stays required even if no active template references it. A
declared optional input becomes required when an active template use needs it.
Optional means it is known not to be required for this context; conditional
means its requirement depends on unresolved context. Do not use optional to
hide uncertainty. Known required declarations retain that classification even
when other requirements are conditional or undiscoverable.
Input entries distinguish declarations from discovered undeclared references
and preserve available descriptions/content types. They do not infer input
schemas or introduce format enforcement. Variables identify caller-map keys,
not template-local symbol names, and report whether each key was supplied.
An empty supplied string is present; absence is separate from classification.
Include statically identifiable undeclared references on known inactive paths
as optional entries with an inactive-use explanation. A required or conditional
use elsewhere takes precedence over that inactive-only classification and
explanation. Inactivity itself is not discovery uncertainty.
Include recognizable references on known inactive paths in both inventories
as optional entries with an inactive-use explanation. Keep explanations separate
from declared input descriptions. An applicable required or conditional use
elsewhere overrides the optional classification. Any applicable occurrence,
including an optional lookup, removes an inactive-only explanation. Known
inactivity introduces neither an execution requirement nor discovery uncertainty.
An unresolved dynamic name can refer to an otherwise optional input entry. Its
absence from recognized active uses alone does not establish that it is
definitely optional; classification and uncertainty must account for that
possibility.
Deduplicate names and provide predictable ordering. Results also identify the
selected context and provide discovery completeness with machine-readable
limitation categories and safe explanations. Exact public spellings belong in
the implementation plan and, once implemented, GoDoc. No Promptkit JSON wire
schema is part of this feature.
Known input names should be deduplicated across declarations, messages, and
session templates. Aggregate uses without discarding an established required
use. Conditions need not expose raw expressions; machine-readable reason
categories and safe summaries are sufficient for basic consumer handling.
## Simple Discovery Boundary
Completeness describes discovery, not readiness or satisfaction. For example,
a missing variable used only to insert text can be a known unsatisfied
requirement while the complete input set is still discoverable. If that
variable selects an input name or branch, its absence can also make discovery
incomplete. An empty complete input set means no artifact bindings are needed;
a complete inventory containing only optional entries also needs no artifact
bindings. An empty incomplete set does not establish that fact. Consumers must
distinguish the inventory from applicable requirements, rather than treating
every reported name as a needed binding.
Use parsed template syntax, not raw-text matching or rendering with placeholder
artifacts. The intended algorithm is straightforward:
## Context-Sensitive Discovery Boundary
1. Seed the inventory from input declarations and their effective metadata.
2. Visit the selected message templates and applicable session template,
collecting recognizable input and caller-variable references.
3. Classify occurrences using their surrounding path and a small amount of
supplied-context evaluation.
4. Aggregate entries and report any unresolved discovery.
Analyze parsed templates rather than searching raw text or rendering with
placeholder artifacts. Use supplied variable values where they determine
branches and input names, following execution's presence, truthiness, scope,
and evaluation semantics. An empty string is not an absent variable, and a
nonempty string must not be reinterpreted as a Boolean merely from its spelling.
The source inventory is finite and ordinarily small. Direct traversal and
name-indexed aggregation are sufficient; no size caps, analysis budgets,
branch-combination enumeration, or global analysis cache are needed.
Include dependencies from messages and the applicable session-ID template.
A direct nonblank session ID bypasses that template, removing only requirements
introduced solely by it; declarations and message uses remain relevant.
The bypassed session template is also excluded from the inactive inventory.
Recognize literal input names, direct caller-variable access, literal-key root
lookups, direct variable-derived input names, and ordinary `if`/`with` branches.
Use simple truthiness, negation, and equality/inequality where straightforward.
Empty strings and the nonempty string `"false"` follow actual Go truthiness.
The implementation plan defines this small initial coverage precisely.
Literal `input` references are discoverable without reading bodies, including
undeclared references. Artifact content being unavailable does not by itself
make discovery incomplete: it does so when the content affects which further
requirements apply. Variable-derived names are discoverable when supported
analysis can determine the exact name from the supplied context.
Retain enough lexical/dot scope awareness to distinguish caller variables from
locals. Complicated assignments, pipelines, computed names, ranges, or invoked
named templates can remain outside complete analysis. Preserve identifiable
references and report limitations rather than implementing a general template
interpreter, joining assignment environments, or propagating possible-name sets.
No cross-branch proof of a common required dependency is necessary.
When missing variables, content-dependent decisions, unresolved names, or
analysis limitations prevent determination, preserve known requirements and
return successful incomplete discovery. Structured reasons should distinguish
these situations without requiring diagnostic-text matching. Unsupported
analysis is not a new prompt-validity rule. Completeness is asserted only when
the supported analysis establishes the requirement set; it does not promise
universal analysis of every valid Go template.
On a known inactive path, collect names visible in syntax without evaluating
its expressions. Literal input names and recognizable caller keys remain in
the inventory; skipped dynamic input names need not be resolved. Unsupported
skipped expressions do not themselves make discovery incomplete.
The selected practical analysis core and inactive inventory are described below.
They do not change execution or expand the template language.
A direct nonblank session ID excludes the bypassed session template from both
inventories. Never-invoked template definitions do not create requirements.
Declarations and references in selected messages remain relevant.
Complex computed names may be missed by the inventory. That is an accepted
analysis limitation, not a reason to reject an otherwise valid prompt.
Inspection must expose potential incompleteness rather than imply that unknown
names are absent. Template authors benefit from keeping dependency expressions
simple, but this feature adds no template-authoring prohibition.
## Completeness And Limitations
Completeness describes discovery, not satisfaction or readiness. A missing
variable used only for direct text substitution can be a known required entry
with complete discovery. A missing value used to select a branch or name can
leave dependencies unresolved.
When unavailable input content, unresolved names, missing decision values, or
unsupported analysis affect discovery, return known entries with successful
incomplete status and structured reasons. Conservative incompleteness is
acceptable; inspection need not prove an exact requirement set through complex
expressions. Unsupported pure text with no effect on dependencies need not
introduce uncertainty.
Unresolved names can potentially refer to existing optional entries. Account
for that possibility in classification, while leaving established required
entries required. Do not label a potentially needed entry definitively optional.
An empty complete input inventory, or a complete input inventory containing
only optional entries, establishes that no artifact bindings are needed.
An empty incomplete inventory does not. Consumers must use classifications,
not inventory length, to identify bindings that need preparation.
## Effects, Errors, And Disclosure
Inspection uses captured prompt resources and needs no future artifact files,
credential lookup, model access, capacity admission, or execution artifact
creation. It does not prepare an output-validation schema or validate future
input bytes. Necessary configuration/resource failures can still prevent engine
construction or inspection; this is not a general resource preflight.
Inspection uses captured resources without future artifact reads, schema
preparation, credential lookup, model calls, capacity admission, observations,
run IDs, or execution artifact creation. Necessary configuration/resource
failures can still prevent engine construction or inspection.
Use existing public selection/error identities wherever applicable, including
invalid requests, missing prompt/profile selections, and ambiguous versions.
Preserve ordinary context cancellation behavior. Discovery uncertainty is a
result state, distinct from an operational or selection error. Expose any
additional necessary classifications through the public facade, not diagnostic
text parsing or internal types.
Preserve publicly classifiable selection errors and ordinary context
cancellation. Discovery uncertainty is a successful result, not an operational
error or a new definition-validity rule. A complete result does not promise
successful rendering, generation, future artifact validity, or provider
availability.
Results and safe diagnostics exclude credential values, artifact payloads,
raw/rendered prompt content, and unrelated supplied variable values. Selected
identities, input/variable names, and declared descriptions are intentional
operator metadata. A resolved dynamic input identifier may equal a supplied
variable value; reporting that identifier is necessary to describe the binding.
Keep the disclosure exception limited to its role as an identifier, without
echoing the variable map or the expression that produced it. Scriptorium owns
the presentation and disclosure of this metadata to its callers.
A complete result describes requirements, not successful rendering or generation,
future artifact validity, or provider availability. Incomplete results remain
useful without authorizing consumers to treat unknown dependencies as absent.
Results and diagnostics exclude credential values, artifact payloads,
raw/rendered prompt content, and unrelated supplied values. Selected identities,
input/variable names, and declared descriptions are intentional operator
metadata. A directly resolved input identifier may equal a supplied variable
value; reporting that binding name is necessary, without echoing its originating
expression or variable map.
## Work Needed From The Baseline
Add public request/result values and the engine method through the existing
facade. Put selection coordination and analysis in internal components with
cohesive ownership. Reuse existing prompt/profile selection, session override,
and template parsing semantics rather than introducing a second preparation
path or a general-purpose template interpreter.
Add request/result values and the engine method through the root facade.
Keep selection coordination internal and place syntax discovery with the
existing prompt-template component. Reuse captured templates and selection
helpers rather than creating another preparation path.
Make the captured templates and effective declaration metadata available to
internal inspection. Retain any required metadata presence at the ConfigKit
handoff. Apply [ADR 0001](../adr/0001-configuration-boundary.md): inspection
interprets final effective definitions, not raw sources, configuration history,
or intermediate artifacts. Operator provenance remains a separate explicit API.
Capture required metadata presence at the final ConfigKit handoff and retain it
alongside inspection snapshots. Apply [ADR 0001](../adr/0001-configuration-boundary.md):
interpret final effective definitions, not raw/intermediate configuration or
history. Operator provenance remains a separate explicit API.
Implement requirement aggregation, context-sensitive analysis, and safe public
uncertainty/error conversion. Keep request-specific analysis separate from
shared captured state. Prefer direct traversals and indexed aggregation; avoid
enumerating every possible branch combination or repeated full-template scans.
Predictable result ordering does not require a stronger complexity guarantee
or a new global cache.
Add focused analyzer tests and public-facade contract coverage under the
[testing policy](../policy/testing.md). Use real captured definitions and
templates, synthetic variables, and explicit unavailable artifacts. Compare
complete discovery with representative execution semantics. Test incomplete
results separately from errors and verify disclosure boundaries and absence
of artifact reads/provider calls. Do not retest ConfigKit's loading matrix.
Implement a small syntax walker, simple context tests, classification
aggregation, and safe limitation reporting. Keep request-specific state separate
from captured definitions. Focus tests on representative enumeration,
classifications, scope mistakes, selection, capture/ownership, and absence of
execution effects, under the [testing policy](../policy/testing.md). Do not test
a general interpreter or repeat ConfigKit's source-loading matrix.
When implementation lands, update GoDoc, the consumer guide, relevant format
cross-references, and the internal component/source documents. Describe the
analysis boundary and examples of complete, unsatisfied, and incomplete results
in their canonical owners. Release notes explain the new capability; they do
not own its contract. The implementation plan owns implementation sequencing.
cross-references, internal documents, and a maintained example. Canonical owners
document the implemented boundary; release notes summarize rather than own it.
## Acceptance Outcomes
- A required `transcript` is reported exactly, allowing a consumer to detect a
planned binding under the wrong name before the transcript exists.
- Literal undeclared helper references are discoverable without making their
absence from declarations a new definition error.
- Declared required inputs remain required in inactive branches; optional
declarations remain optional where no applicable use makes them required.
- Statically identifiable inactive undeclared references are optional entries
with an inactive-use explanation; active and unresolved uses of the same name
take precedence. These entries do not introduce variable requirements or
incompleteness solely from skipped expressions.
- Supported variable-dependent branches and names agree with execution;
unresolved content/name/analysis cases retain known entries and uncertainty.
- Version/profile/default selection and session-template bypass agree with
execution without credential or generation-readiness checks.
- Variables are reported separately, with absent and empty supplied values
interpreted according to the existing template semantics.
- Artifact-free complete results, including all-optional inventories, are
distinguishable from empty partial discovery.
- Errors remain publicly classifiable; results and safe diagnostics disclose
identifiers and declared metadata without unrelated content or secret values.
- Existing inspection and execution APIs retain their contracts. Pipeline
planning, binding validation, CLI/HTTP exposure, presentation, JSON schemas,
graph rendering, batch interfaces, and provider preflight remain downstream.
## Selected Analysis Scope And Inventory
### Initial Template Analysis Coverage
Implement a documented practical core: literal input calls,
direct caller-variable access, ordinary `if`/`with` control flow, and simple
variable-derived names and comparisons where their values are determinable.
Account for template variable scope and short-circuit behavior for supported
expressions. Additional constructs can be supported where straightforward;
otherwise report incompleteness when they affect requirement discovery. The
implementation plan specifies the exact expression families for this baseline.
This covers the representative consumer needs while keeping completeness
honest and avoiding a second general-purpose interpreter.
### Inactive Undeclared Reference Inventory
Always include declarations and discovered active or unresolved dependencies.
Also include statically identifiable undeclared references on known inactive
paths as optional entries with an inactive-use explanation. This broader
inventory helps operators explore prompt behavior while preserving the
distinction between inventory and applicable dependencies.
Collect inactive names from syntax without evaluating skipped expressions.
The initial scope covers literal helper names and equivalent parenthesized or
piped literal forms. Skipped dynamic names need not be resolved, and skipped
variable accesses do not become caller requirements or uncertainty reasons.
Include known skipped branches and short-circuit operands, without expanding
analysis to never-invoked template definitions or a bypassed session template.
Preserve declared optional metadata and required declarations; when another
use makes a name required or conditional, its inactive occurrence does not
override that classification or imply that the name is inactive-only.
- Required `transcript` is reported exactly before its artifact exists.
- Literal undeclared helper names are discoverable without definition rejection.
- Input and variable references are classified as required, conditional, or
optional, including recognizable inactive references in both inventories.
- Required declarations stay required; definite uses promote optional entries;
other occurrences never erase an established required use.
- Simple supplied-context branches and direct dynamic names follow execution;
complicated or content-dependent cases preserve known entries and limitations.
- Caller keys remain distinct from template locals, and supplied empty values
remain distinct from absent keys.
- Selection and session bypass follow execution without readiness checks.
- Complete artifact-free inventories remain distinguishable from empty partial
discovery; completeness remains separate from supplied-variable presence.
- Results/errors preserve the disclosure and public classification boundaries.
- Existing inspection/execution contracts remain intact. Application APIs,
pipeline planning, binding validation, presentation, provider preflight, input
schemas, and a general-purpose template evaluator remain outside this scope.