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,55 +1,46 @@
# Effective Prompt Requirement Inspection Implementation Plan # Effective Prompt Requirement Inspection Implementation Plan
Implement the [feature roadmap](inspection.md) in order. Each numbered stage Implement the [feature roadmap](inspection.md) in order. Each numbered stage is
is scoped for one Luna coding-agent prompt. This plan replaces the completed scoped for one Luna coding-agent prompt. This plan replaces the earlier
ReleaseKit adoption plan; that plan remains available in Git history. interpreter-style analysis scope with simple enumeration and conservative
classification. The completed ReleaseKit plan remains available in Git history.
## Baseline And Working Rules ## Baseline And Working Rules
- Baseline: `7827ca043b5de84a18199ac8f4b3056691aacbb5`. There is no effective - Planning baseline: `e459c7d`. The inspection API is not implemented.
requirement-inspection API yet. `InspectPrompt` reports declarations; `InspectPrompt` reports declarations, `Prepare` needs artifacts, and the
`Prepare` needs artifacts. The configured engine captures compiled templates. configured engine already captures compiled templates.
- The agreed scope is the practical analysis core, with statically identifiable - Start with [development](../development.md), then the
inactive undeclared input references included as optional inventory entries
and explained as inactive. Distinguish this inventory from applicable
dependencies; it does not require evaluating skipped expressions or adopting
broader Go-template interpretation.
- Start with [development](../development.md), then read the
[agent](../policy/agents.md), [architecture](../policy/architecture.md), [agent](../policy/agents.md), [architecture](../policy/architecture.md),
[testing](../policy/testing.md), and [documentation](../policy/documentation.md) [testing](../policy/testing.md), and [documentation](../policy/documentation.md)
policies. Reuse unchanged policies already read. Follow policies. Reuse unchanged policies already read.
[ADR 0001](../adr/0001-configuration-boundary.md): interpret final effective - Follow [ADR 0001](../adr/0001-configuration-boundary.md): interpret only final
configuration at the ConfigKit handoff, never raw/intermediate sources or effective configuration at the ConfigKit handoff. Operator provenance is
configuration history. separate; inspection does not examine raw sources or intermediate values.
- Inspect the current worktree before each stage; preserve unrelated work. - Preserve unrelated work and commit completed, verified units under the agent
Validate and commit each completed unit under the agent policy. Keep current policy. Keep implemented internal documentation accurate as stages land.
internal documentation accurate as each internal capability lands. - Preserve existing construction, inspection, preparation, rendering, and
- Preserve all existing inspection, construction, preparation, rendering, and execution contracts. An inspection limitation is not a definition error.
execution contracts. Discovery limitations must not invalidate templates. - Use captured parsed syntax, direct traversal, and maps keyed by exact name.
Do not add variable defaults, input schemas, name restrictions, count/size No general evaluator, assignment-value propagation, branch-environment joins,
limits, a branch-expansion budget, or generation-readiness checks. possible-name sets, branch combinations, analysis budget, or global cache is
- No provider calls, actual publication, new dependency, CLI/HTTP layer, upstream needed. Do not add caller limits, defaults, input schemas, or authoring bans.
ConfigKit change, or application-specific pipeline concept is needed. - The root package owns public declarations/conversion. `internal/prompt`
- Public declarations belong in the root facade; analysis belongs in owns discovery, `internal/usecase` coordinates selection, and
`internal/prompt`, selection coordination in `internal/usecase`, and metadata `internal/configuration` supplies captured syntax/metadata. Runtime/domain
capture in `internal/configuration`. Runtime/domain values remain independent values remain independent of ConfigKit.
of ConfigKit. Use the standard parser and `template.IsTrue`; do not implement - No new dependency, upstream ConfigKit change, provider access, CLI/HTTP
a replacement template language or execute whole prompts with fake artifacts. feature, application wire format, or publication is part of these stages.
## Concrete API And Result Decisions ## Concrete Public Values
Add root `requirements.go` in Stage 8. The method is: Add root `requirements.go` in Stage 5:
```go ```go
func (e *Engine) InspectRequirements( func (e *Engine) InspectRequirements(
ctx context.Context, req RequirementInspectionRequest, ctx context.Context, req RequirementInspectionRequest,
) (*RequirementInspection, error) ) (*RequirementInspection, error)
```
Define ordinary root-owned values, mirrored by execution-owned internal values
in `internal/domain/requirements.go`; do not export aliases to internal types:
```go
type RequirementInspectionRequest struct { type RequirementInspectionRequest struct {
PromptID string PromptID string
PromptVersion string PromptVersion string
@@ -58,7 +49,7 @@ type RequirementInspectionRequest struct {
SessionID string SessionID string
} }
type RequirementKind string // constants: required, optional, conditional type RequirementKind string // values: required, conditional, optional
type InputRequirement struct { type InputRequirement struct {
Name string Name string
@@ -70,9 +61,10 @@ type InputRequirement struct {
} }
type VariableRequirement struct { type VariableRequirement struct {
Name string Name string
Kind RequirementKind Kind RequirementKind
Supplied bool Supplied bool
Explanation string
} }
type RequirementIssueCode string type RequirementIssueCode string
@@ -95,495 +87,355 @@ type RequirementInspection struct {
} }
``` ```
Use `RequirementRequired`, `RequirementOptional`, and Use root-owned values and internal counterparts in
`RequirementConditional` as the kind constant names. Use these issue constants: `internal/domain/requirements.go`; do not expose internal aliases.
Kind constants are `RequirementRequired`, `RequirementConditional`, and
`RequirementOptional`. Retain four useful issue categories:
| Constant | Value | Meaning when discovery is affected | | Constant | Value | Discovery limitation |
| --- | --- | --- | | --- | --- | --- |
| `RequirementIssueMissingVariable` | `missing_variable` | An absent caller value prevents resolving a dependency decision/name. | | `RequirementIssueMissingVariable` | `missing_variable` | An absent value prevents determining a dependency decision/name. |
| `RequirementIssueInputContent` | `input_content` | Unavailable artifact content affects further dependencies. | | `RequirementIssueInputContent` | `input_content` | Unavailable artifact content affects dependencies. |
| `RequirementIssueDynamicInputName` | `dynamic_input_name` | A helper's exact selected name remains unresolved. | | `RequirementIssueDynamicInputName` | `dynamic_input_name` | A referenced input name cannot be determined. |
| `RequirementIssueUnsupportedConstruct` | `unsupported_construct` | A construct outside the analysis core prevents discovery. | | `RequirementIssueUnsupportedConstruct` | `unsupported_construct` | Analysis does not cover a dependency-relevant expression or scope. |
| `RequirementIssueExpressionUnresolved` | `expression_unresolved` | An expression cannot be evaluated within the supported semantics, including an incompatible operation. |
Use safe, fixed-category descriptions, optionally identifying reported names. An empty associated name means that no particular entry was identified.
Do not expose the expression, its literals unrelated to identifiers, its Descriptions and explanations are safe human-readable summaries, not strings
evaluated values, raw template text, or a Go template execution error. An empty callers must parse. There is no expression tree, source offset, JSON tag/schema,
associated name means no particular named entry is identified; it does not or stable diagnostic wording contract.
establish that an input/variable is absent.
### Classification, Metadata, And Ownership ### Classification And Ownership
- Always report declarations. A declared required input stays required. - Seed declared inputs from final effective definitions. Required declarations
Active template accesses can promote an optional declaration to required. stay required independently of syntax. Others start optional.
Include statically identifiable undeclared references on known inactive paths - Collect occurrences with definite, possible, or inactive reachability.
as optional entries with an inactive-use explanation. Definite helper/direct required-variable accesses are required; possible ones
- An entry is required when its use is established for the context, conditional are conditional; recognizable inactive references are optional. A lookup
when a possible use depends on unresolved analysis, and optional when no that execution permits to be absent remains optional unless another access
applicable use needs it and unresolved effects do not undermine that conclusion. establishes a stronger requirement.
An established required use dominates conditional/optional uses. - Aggregate exact names with required > conditional > optional. No proof that
- `Explanation` is a safe human-readable summary of inactive-only use, separate a name in both unresolved branches is required is necessary: conditional is
from declared `Description`. Its wording is not a machine-readable contract. acceptable until an independent definite access/declaration establishes it.
Do not add an uncertainty issue for known inactivity. Required or conditional - Include recognizable inactive inputs and caller variables in both inventories.
uses elsewhere override inactive-only classification and explanation. Give inactive-only entries an `Explanation`, independent of declared input
Caller variables used solely on known inactive paths are not requirements. `Description`. Any applicable occurrence, including an optional lookup,
- Aggregate inputs and variables by exact execution name. Do not trim request removes the inactive-only explanation; required/conditional uses also
variable keys or discovered helper names. Configuration normalization remains override optional classification. Inactivity is not an uncertainty issue.
with the existing configuration adapter. - Input metadata pointers distinguish absence/null from an explicit string,
- Metadata pointers distinguish absent/cleared metadata from an explicit including an empty string. `Declared` distinguishes metadata ownership from
value, including an explicitly empty value. `Declared` distinguishes a known a helper-only reference. Do not infer new input formats.
declaration from a helper-only reference. No new input-format enforcement. - `Supplied` means presence of the exact caller key, including empty strings.
- `Supplied` is key presence in the caller's variable map, including an empty It is independent of classification and completeness; do not echo values.
string. A required variable's presence satisfies that known presence - Sort input and variable entries lexically by exact name. Deduplicate issues
requirement; a conditional variable's necessity is unresolved. Optional by code/input-name/variable-name and sort by that tuple. Do not promise a
lookup absence is not a missing required value. Do not infer Boolean values, nil-versus-empty slice distinction.
nonblank constraints, or other variable validation from names. - Return independent slices and metadata pointers, copy request variables at
- Sort inputs and variables lexicographically by exact name. Deduplicate issues the facade as for `RunRequest`, and keep captured syntax immutable. Retain
by code/input-name/variable-name and sort by that tuple. Diagnostics need no callers' existing responsibility for concurrently mutating requests.
public expression tree, node offsets, or JSON tags. No stable wire format or
nil-versus-empty slice distinction is promised.
- Return independent slices and metadata pointers; copy request variables at the
facade like `RunRequest`. Never expose or mutate shared template trees.
Callers retain the existing responsibility for concurrent mutation of requests.
### Completeness And Uncertainty ### Deliberately Small Recognition Scope
`Complete` concerns discovery of both input and variable requirements, not Use the standard template parse tree and `template.IsTrue` for known values.
whether they are satisfied. `{{.audience}} {{input "note"}}` can yield complete Only determine a value when needed for a recognized name or simple condition.
discovery with a missing required `audience` and known required `note`.
Reading the body of `note` is unnecessary to identify that dependency.
An empty complete input set, or a complete inventory containing only optional
entries, establishes that no artifact bindings are needed. Nonempty inventory
alone does not establish that artifacts are needed; incomplete discovery does
not establish their absence.
Unknown values carry their cause internally. Emit issues and mark incomplete | Syntax | Initial handling |
when uncertainty affects a dependency decision/name, or an opaque construct
can hide requirements. Unknown output text alone does not cause incompleteness.
An unknown branch containing only text need not make discovery incomplete.
For an unresolved branch, analyze both paths once and combine access summaries:
a name definitely needed on both paths can stay required; names possible on
only some paths are conditional. Merge branch-local unresolved issues.
Compare applicable requirement summaries, not inactive inventory or rendered
content, and do not enumerate combinations of independent conditions.
Conservative incompleteness is valid
where the core cannot prove an exact set; do not claim completeness there.
Unresolved dynamic names/opaque input effects must not leave otherwise optional
input entries falsely definitive. Mark affected optional entries conditional,
including previously inactive-only undeclared entries; an unrestricted unknown
input name can affect all such entries. Clear inactive-only explanations where
possible active uses undermine them.
An unknown-name issue also describes potential undiscovered undeclared names.
Known required declarations remain required.
### Initial Analysis Core
Analyze each selected template's executable root. Definitions that are never
invoked do not themselves create requirements.
| Construct | Initial handling |
| --- | --- | | --- | --- |
| Text/comments and sequences | No text output; visit executable actions in order. | | Literal `input "name"` | Collect the exact name without reading its body. Parenthesized literal wrappers and a literal piped directly to `input` are equivalent. |
| String, Boolean, nil literals; dot/root | Track known values needed for dependencies; root is the supplied string map. | | Direct root `.name` or `$.name` | Collect a required caller key when active; supplied strings are known, absence is unresolved rather than an inspection error. |
| Root-map field access, including `$.name` | Record a required named caller variable; absent key produces an unknown value, not an inspection error. | | `index` of the root map with one literal string key | Collect an optional lookup; its value is supplied text or the string zero value if absent, following execution. |
| Dot inside `with` | Follow the selected pipeline value; do not reinterpret string fields as caller root keys. | | `input .name`, `input $.name`, or `input (index . "name")` | Resolve a directly available string as an input identifier on applicable paths. |
| `index` on the root map with a known string key | Record an optional named lookup, unless another use requires it; absent lookup yields the Go string zero value. | | One simple value piped directly to `input`, or parenthesized simple expressions | Recognize the same bounded forms without evaluating arbitrary pipelines. |
| Local variables | Single-variable declarations and assignments, root `$`, aliases, lexical scope, and pipeline results; locals are not caller variables. | | String/Boolean/nil literals and simple direct values | Use known values for conditions; no coercion of caller strings. |
| `input` | Known string names, including direct variable/alias-derived names; record the dependency and return an unknown body value. | | `not` of a simple predicate; two-string `eq`/`ne` | Recognize negation and ordinary equality/inequality without adding the full comparison family. |
| Pipelines/parenthesized expressions | Respect argument order and the previous value's final-argument position. | | `if`/`else`, `with` | Classify branch occurrences using a recognized condition; unresolved branches are possible, not guesses. |
| `and`, `or`, `not` | Go truthiness and short-circuit access semantics; return Go-compatible operand/Boolean values. | | Locals, changed dot, and root binding | Retain scope identity sufficient to distinguish root-map accesses from local/string/unknown values; no local-value propagation is required. |
| `eq`, `ne`, `lt`, `le`, `gt`, `ge` | String comparisons, including `eq`'s multiple comparison operands; all ordinary arguments are evaluated as Go does. | | Other pipelines/functions, `and`/`or`, assignments, ranges, invoked named templates, or complex names | Collect safely identifiable references conservatively and record dependency-relevant limitations; do not interpret their execution. |
| `if`, `else`, `with` | Known-path selection and unresolved-path joining, with correct dot/local scope. |
| Numeric operations, other built-ins, ranges, invoked named templates, other constructs outside the core | Keep discovered dependencies and expose uncertainty when they affect discovery. Do not reject the definition or execute loops/calls speculatively. |
A numeric literal or unsupported pure output expression is not itself a caller An unsupported expression does not automatically make every argument a definite
requirement. Discover its evaluated arguments where that is safe; its value can access: short-circuiting or unknown scopes can make references merely possible.
remain unknown until a later dependency decision needs it. Known short-circuit Keep complex forms outside complete analysis instead of emulating their rules.
paths must not collect dependencies from skipped operands or branches. Do not interpret `$local` as a caller key or `.field` on a string/unknown dot as
They can contribute optional inactive inventory as described below, without a root lookup. Explicit root accesses remain recognizable only while the root
collecting skipped caller-variable requirements or uncertainty. binding's identity is known. Unsupported changes to a binding make its identity
unknown where affected; no assignment-value or cross-branch reconstruction is
needed.
For a known inactive path, use a non-evaluating syntax walk to collect literal Walk known inactive subtrees for syntactically identifiable literal input names
`input` names, including equivalent parenthesized/piped literal forms. Walk and caller keys. Do not evaluate skipped expressions, resolve skipped dynamic
skipped branch bodies and short-circuit operands without reading caller values, input names, or produce uncertainty solely from skipped constructs. Names
mutating local environments, or invoking templates/functions. Unresolved hidden behind unsupported scopes need not be invented. Exclude bypassed session
dynamic names and unsupported expressions in these skipped paths do not make templates and never-invoked definitions entirely.
discovery incomplete. Never-invoked definitions and a directly bypassed session
template remain outside this inventory. Track inactive-only occurrences
separately from definite/possible uses so aggregation can classify a shared
name correctly.
Use a small private known/unknown value model. Branch joins retain identical ### Simple Algorithm And Completeness
known values and can retain finite possible string names from direct
string-valued branch assignments. Different possible names are conditional;
a missing variable/body or opaque value can introduce other unknown names.
Do not evaluate cross-products of possible expression values or build a symbolic
predicate system. Unsupported scopes must not invent root variable names:
preserve explicit root accesses and literal helper references where identifiable,
and report incompleteness for the rest.
## Stage 1 — Retain Effective Declaration Metadata And Inspection Snapshots 1. Seed declaration entries and visit each selected template.
2. Maintain only reachability and the scope identity needed to recognize caller
keys; collect names and minimal classification evidence in indexed summaries.
3. For simple conditions, visit both branches with definite/possible/inactive
reachability as appropriate. A possible parent never becomes definite just
because an inner predicate is known true; a known inactive parent stays
inactive. No branch environment or assignment-value joins are needed.
4. Aggregate/finalize names, metadata, presence, explanations, and limitations.
**Outcome:** Inspection can obtain captured templates and metadata without Use shared traversal helpers for active/possible/inactive syntax rather than
changing execution definitions, hashes, or existing public inspection values. separate interpreters. Do not enumerate execution combinations. Prefer a direct
pass through syntax and final aggregation; no special machinery is warranted
by ordinary prompt sizes.
`Complete` means that the supported analysis established the requirement
inventory/classifications. Conservative false is acceptable for difficult cases.
Missing direct text-substitution values alone do not make discovery incomplete.
Unresolved branches with dependency-bearing references return conditional
entries and incomplete status; no proof of identical branches is required.
Unknown pure text without a dependency effect need not change completeness.
An unsupported call that may hide dependencies or an unresolved active input
name makes discovery incomplete. Preserve recognized names; do not create a
wildcard entry. Maintain simple flags for possible unknown input/caller-key
effects, promoting affected optional entries to conditional at finalization,
rather than repeatedly rescanning the inventory. Known required entries remain
required. Clear inactive-only explanations where those unknown effects undermine
the conclusion.
A complete empty or all-optional input inventory needs no artifact bindings.
An incomplete inventory does not prove that no others are needed. A complete
result is not a rendering/readiness/provider guarantee.
## Stage 1 — Capture Effective Metadata And Template Snapshots
**Outcome:** The analyzer can obtain existing compiled templates and declaration
metadata without artifact reads or changing old inspection/execution behavior.
**Read:** `internal/configuration/load.go`, `prompts.go`, **Read:** `internal/configuration/load.go`, `prompts.go`,
`internal/prompt/template.go`, `internal/domain/domain.go`, `internal/prompt/template.go`, `internal/domain/domain.go`,
`internal/promptdef/hash.go`, and the source document. `internal/promptdef/hash.go`, and the internal source document.
**Work:** **Work:**
1. Add internal metadata/snapshot values. Retain content-type/description 1. Retain content-type/description presence alongside configuration
presence alongside `promptEntry`, not inside the JSON-hashed `promptEntry`, rather than changing the hashed prompt definition or old
`domain.PromptDefinition` or the existing public `PromptInputDefinition`. public inspection shape.
2. Capture effective per-input presence from `Resolution.InputInfo` during the 2. Capture effective per-input presence from `Resolution.InputInfo` during the
existing Resolve callback before `resolvePrompts` can record normalized existing Resolve callback before prompt normalization. Use final
sequences. Use final prompt-ID/version/input-index paths only, following the prompt-ID/version/input-index paths, following the existing presence-capture
existing backend/profile presence-capture pattern. Do not inspect history. pattern. Materialize values from the normalized final declaration.
3. Materialize metadata values from the normalized final declaration. Treat 3. Add `prompt.RequirementSnapshot` with captured templates and metadata, and
absent/null as no metadata and an explicit empty string as available metadata; narrow internal `GetRequirementSnapshot(id, version string)
preserve existing accepted/rejected configuration semantics. (RequirementSnapshot, bool)` access on the captured configuration adapter.
4. Define `prompt.RequirementSnapshot` containing compiled templates and Use selected exact keys, without reparsing or reopening resources.
declaration metadata, plus the narrow internal lookup 4. Preserve renderer/constructor paths and update internal source documentation.
`GetRequirementSnapshot(id, version string) (RequirementSnapshot, bool)`.
Implement it on the captured configuration adapter. Use exact selected keys
and read-only template access; do not parse/reopen content during lookup.
5. Keep the existing renderer's lookup and all old constructor/API paths intact.
Update the internal source document for the implemented metadata capability.
**Verify:** Focused configuration tests cover absent, empty, nonempty, and **Verify:** Focused final-value metadata tests for absent/null, empty, and
normalization-sensitive metadata, with real final-value layering/resource capture. nonempty values, plus equivalent-definition hashes and old inspection behavior.
Confirm old inspection shape and definition hashes remain unchanged for equivalent Use actual configuration capture rather than another source-loading matrix.
existing definitions. Run `go test ./internal/configuration ./internal/promptdef ./internal/prompt`. Run `go test ./internal/configuration ./internal/promptdef ./internal/prompt`;
Commit this unit; do not implement the public method yet.
## Stage 2 — Add Internal Result Values And Literal Dependency Discovery
**Outcome:** Straight-line literal helper requirements and declarations are
discoverable through an internal analyzer.
**Work:**
1. Add internal counterparts of the result kinds, metadata, and issue values
defined above in `internal/domain/requirements.go`.
2. Add `internal/prompt/requirements.go` and focused tests. Provide one analyzer
entry taking context, selected definition, captured snapshot, variables, and
whether session-template analysis is bypassed; return internal analysis data.
Selected public identities will be added by the runner later.
3. Seed declarations, walk executable root actions, recognize literal
`input "name"` calls, deduplicate names, and aggregate required accesses.
Analyze the session first when applicable and messages in their existing order.
4. Add aggregation/finalization helpers for classification, independent metadata,
ordering, safe explanations/issue construction, and `Complete`. Keep
inactive-only occurrence information separate from applicable accesses for
Stage 5. Do not produce prompt text.
5. Until later stages implement control flow, return conservative incomplete
results for constructs that can hide dependencies. Temporary partial coverage
is internal implementation status, not a new public promise.
6. Check context at ordinary traversal boundaries; return the context error,
not a successful partial result after cancellation. Do not introduce workers,
hard analysis limits, or stronger interruption promises.
7. Describe implemented analysis ownership in the component/source documents.
**Verify:** Straight-line declared/undeclared references, duplicates, declared
required unused inputs, optional unused declarations, literal body independence,
empty input-free templates, and session-only references. Run
`go test ./internal/prompt ./internal/domain`; commit.
## Stage 3 — Resolve Caller Values, Map Lookups, And Local Aliases
**Outcome:** Caller variable requirements are distinct from input requirements;
simple names and pipeline values can be tracked without rendering.
**Work:**
1. Implement private value/environment records for known strings/Booleans/nil,
root-map identity, local symbols, and unknown values with causes.
2. Handle direct root field accesses and `$.name`, absent versus empty string,
root-map `index` with known string keys, local declarations/assignments, and
parenthesized/pipeline argument binding.
3. Caller requirements arise from accesses to the root variable map, not local
symbol names. Direct field access is required; optional `index` access is
promoted if another active use requires that same caller key.
4. Keep missing values unknown without aborting discovery. Do not mark incomplete
solely because a text-substitution variable is absent.
5. Preserve exact keys and values internally; return only requirement metadata
and key-presence information. Add no coercion, trimming, or field-name limits.
**Verify:** Direct supplied/missing/empty values, optional lookups, duplicate
access promotion, root versus local names, and pipeline argument position.
Use small comparisons with real Go-template execution for presence behavior;
do not duplicate the standard library's entire test matrix. Run
`go test ./internal/prompt`; commit.
## Stage 4 — Add Core Comparisons And Short-Circuit Semantics
**Outcome:** Common context expressions select values and dependencies consistently
with Go templates.
**Work:**
1. Implement `not`, string comparison families, and the operand-returning
`and`/`or` behavior specified in the core table. Use `template.IsTrue`.
2. Evaluate ordinary command arguments in order; `eq`'s multiple comparison
operands are not an `or` shortcut. Short-circuit only the appropriate
`and`/`or` operands.
3. Once a preceding operand leaves access uncertain, treat later potentially
evaluated operands conditionally rather than definitely accessed or skipped.
Preserve unknown causes for later dependency decisions.
Stage 5 adds optional inventory for definitely skipped helper expressions;
these are not applicable input or variable dependencies.
4. Keep unsupported/incompatible evaluation as an internal unknown value with
a safe category. Do not leak values through errors or convert it into a new
construction/request rejection.
5. Inspect safe eager arguments of out-of-core built-ins for dependencies.
Their output may remain unknown; never execute arbitrary functions or whole
templates merely to determine a dependency.
**Verify:** Empty/nonempty strings, the truthiness of the string `"false"`,
comparisons, multi-operand `eq`, and `and`/`or` skips containing helper calls
or missing variables. Compare representative supported expressions with the
existing Go renderer. Run `go test ./internal/prompt`; commit.
## Stage 5 — Analyze Known Branches, Scope, And Inactive Inventory
**Outcome:** Supplied context resolves ordinary `if`/`with` dependencies;
statically identifiable inactive input references remain optional inventory.
**Work:**
1. Add `if`/`else` and `with` traversal for known predicate values.
Evaluate only the selected path for applicable dependencies.
2. Preserve root `$`, `with` dot changes, pipeline-declared symbols, block
shadowing, and assignments to outer symbols. Follow Go's lexical lifetimes.
3. Never reinterpret `.field` against a known string dot as a root-map lookup.
Unsupported field operations have unknown values, not invented variables.
4. Add the non-evaluating inactive syntax walk specified above. Include literal
helper names from skipped branches and short-circuit operands as optional
entries with a safe inactive-use explanation. Preserve declarations and
aggregate other uses of the same name; required/conditional uses dominate.
5. Do not evaluate skipped predicates, resolve skipped dynamic names, mutate
branch environments, or collect skipped caller-variable requirements/issues.
Do not inspect uncalled definitions or a bypassed session template.
6. Keep uncertain predicates using the temporary conservative handling until
Stage 6; do not guess their truth from placeholders.
**Verify:** Both known branches, nested `if`/`with`, root access from changed dot,
declarations versus assignments/shadowing, and inactive helpers/missing variables.
Include declared-required and declared-optional inputs in these cases.
Test inactive undeclared literal and equivalent parenthesized/piped names,
inactive explanations, active reuse overriding inactivity, and skipped dynamic
or unsupported expressions causing no uncertainty. Verify that a complete
all-optional inventory requires no artifacts.
Run `go test ./internal/prompt`; commit.
## Stage 6 — Join Unresolved Paths And Finalize Completeness
**Outcome:** Missing values and content-dependent branching return useful partial
results without inventing definitive classifications.
**Work:**
1. Analyze unknown branches once each in forked local environments. Join their
requirement summaries and any assignments visible after the block. Preserve
identical known values; retain direct possible string names where available.
2. Required accesses shared definitely across both paths can remain required.
Otherwise possible accesses are conditional. An unconditional use elsewhere
or a declared required input still dominates.
3. Emit uncertainty only when it affects discovered requirements. An unresolved
text-only branch can still have a complete requirement set; no output rendering
is needed to establish that. Inactive inventory entries alone do not change
applicable dependency summaries or introduce incompleteness.
4. Support input-body-caused unknown conditions without reading the body:
the predicate's known helper name is required; dependent branches are partial.
5. Handle out-of-core controls/calls conservatively. Inspect identifiable
literal helper and explicit root-variable accesses where scope is known.
Do not follow recursive named calls, unroll ranges, or mark unrelated locals
as caller variables. Opaque hidden requirements must keep the result incomplete.
6. Ensure supported and unsupported analysis does not mutate compiled templates
or change definition acceptance. No new parser/compiler validation rule.
**Verify:** Unknown branch unions and shared accesses, missing text variables
with complete discovery, branch-sensitive missing variables, content predicates,
unknown `with` dot, assignment joins, and valid range/named-template examples
returning incomplete rather than errors. Run `go test ./internal/prompt`; commit.
## Stage 7 — Finish Dynamic Names And Conservative Inventory Aggregation
**Outcome:** Direct variable/alias names resolve exactly; unresolved names
preserve known candidates and correctly affect optional inventory classifications.
**Work:**
1. Resolve `input .input_name`, root `index` results, aliases, parenthesized
arguments, and piped names when the supported value is one known string.
Supplied name values are used as identifiers, never normalized anew.
2. For joined finite possible string names, report their possible input entries
conditionally. For unrestricted unknown names, retain all already known
entries and report undiscovered-name uncertainty.
3. Emit dynamic-name issues together with useful missing-variable, input-content,
unsupported, or expression-unresolved categories from the underlying value.
Do not echo values beyond a resolved/known possible binding identifier.
4. Make potentially targeted optional input entries conditional: candidate-only
uncertainty affects matching entries; unrestricted/opaque input effects
can affect all optional entries, including inactive undeclared inventory.
Remove inactive-only explanations when possible active uses undermine them.
Leave known required inputs required.
5. Finalize deduplication, lexical ordering, metadata propagation, variable
`Supplied` flags, inactive-use explanations, and completeness. No placeholder
`"*"` input name, invented variable default, payload read, or binding-validation API.
**Verify:** Exact dynamic names, empty supplied values versus missing values,
aliases selected by known branches, finite names from unknown assignments,
unrestricted names, repeated uses across messages/session, and optional
declaration/inactive inventory uncertainty. Verify results contain no unrelated
variable values or skipped-variable requirements.
Run `go test ./internal/prompt`; commit.
## Stage 8 — Wire Selection And The Public Engine Facade
**Outcome:** A configured consumer can call the new operation without artifacts,
credentials, schema preparation, or execution collaborators.
**Work:**
1. Add `internal/usecase/requirements_inspection.go` and the internal request.
Check nonblank prompt ID, normalize the direct session ID using the existing
domain helper, and honor context cancellation before selection work.
2. Use `resolvePromptDefinition` for exact version/default ambiguity behavior.
Factor the existing request-profile/default-profile choice into a small
shared private helper at its existing preparation location, retaining its
error identities and preparation error ordering.
3. Use `resolveProfileSelection` only to select identity. Do not call
`resolvePreparation`, target-completeness checks, API-key validation,
credential environment lookups, artifact/schema readers, renderer,
validator, admission, generation, or observation/run-ID machinery.
4. Obtain the captured requirement snapshot through the narrow lookup capability
on the selected repository. A configured production engine always provides
it. Missing internal capability/snapshot is an operational `ErrPromptLoad`,
not successful incomplete discovery or a raw-template fallback.
5. Analyze the messages and applicable session template; direct nonblank session
bypass removes only that template's uses. Build the internal result with the
selected identities and forward through `internal/engine`.
6. Add the public values/method in root `requirements.go`, conversion helpers,
GoDoc, and normal `mapPublicError` translation. Copy mutable values as above.
Document inactive inventory and `Explanation` separately from declaration
metadata and structured uncertainty; do not promise diagnostic wording.
Nil engine matches `ErrInvalidConfig`; operational errors return no partial
result. Successful incomplete discovery returns a result and nil error.
7. Preserve existing public error categories for absent prompt/profile,
ambiguous versions, absent selected/default profile, invalid session ID, and
cancellation. Add no new sentinel merely for uncertainty.
8. Update internal component/runner documentation for the implemented method.
**Verify:** Focused runner tests with failing/counting execution collaborators
prove selection-only behavior. Check explicit/default/partial profiles,
exact selectors and ambiguity, session bypass, cancelled contexts, nil engine,
and incomplete-success behavior. Run
`go test ./internal/usecase ./internal/engine ./...` once for facade wiring;
commit. commit.
## Stage 9 — Protect Public Semantics, Isolation, And Execution Parity ## Stage 2 — Enumerate Literal Inputs And Caller Keys
**Outcome:** Consumer-facing tests cover the acceptance outcomes without **Outcome:** An internal syntax walker produces deduplicated inventories and
duplicating the analyzer's detailed case matrix. does not confuse caller variables with template locals.
**Work:** **Work:**
1. Add external-package `requirements_inspection_contract_test.go` using real 1. Add internal result counterparts in `internal/domain/requirements.go` and
configured engines and minimal synthetic definitions. Use the existing an analyzer entry in `internal/prompt/requirements.go`, taking context,
mapping/profile helpers, not a downstream checkout. selected definition/snapshot, supplied variables, and session bypass.
2. Prove exact `transcript` discovery, undeclared literal inputs, required and 2. Seed declarations, visit executable message roots and the applicable session
optional declarations in inactive branches, context-selected names, and root, and collect literal input references and direct/literal-index caller
session-only requirements removed by a direct session ID. keys. Exclude uncalled definitions and a bypassed session template.
Include optional inactive undeclared entries with explanations, active reuse 3. Implement aggregation, exact names, supplied-key presence, independent
overriding inactivity, and bypassed session names absent from the inventory. metadata, sorting, and safe issues/explanations. Add ordinary traversal
3. Cover complete-but-unsatisfied variable requirements, conditional/unknown cancellation checks without stronger interruption promises or workers.
dependencies, and empty complete versus empty incomplete input sets. 4. Track scope identity, not local values: root-map versus nonroot/unknown dot
Cover complete all-optional inventories and no caller requirements from and local bindings. For unsupported scope changes, keep safely recognizable
solely inactive variable accesses. references and report incomplete analysis rather than inventing caller keys.
4. Preserve classifiable errors for selection/cancellation. Test inspection 5. Until Stage 3, classify branch references conservatively as possible and
against a valid partial profile and an explicit direct-key-required profile unsupported dependency-bearing expressions as limitations.
without an API key; missing runtime schemas and future artifact files must 6. Update the implemented internal component/source descriptions.
not prevent inspection. Inject fail-if-called artifact/model/validator
collaborators where supported to prove the relevant absence of execution.
5. Use a small parity table: known-context applicable inspector requirements
must agree with `Prepare`/the renderer's input and variable semantics when
actual synthetic artifacts are later supplied. Do not use execution failure
order as the definition of all discovered requirements.
Do not compare optional inventory entries to actual renderer helper accesses.
6. Test source capture using a file-backed message changed/deleted after engine
construction. New inspection uses the captured content, like existing runs.
7. Mutate returned metadata/slices and repeat inspection; run representative
simultaneous inspections alongside preparation to verify no shared-state
mutation. Test this ownership risk, not a new scheduling/order guarantee.
8. Verify safe diagnostics/result formatting with marker values: unrelated
variable values, direct session value, template text, and credential values
are absent; input identifiers and declared descriptions are allowed.
Include inactive explanations in the disclosure checks.
9. Keep analyzer tests as the owner of detailed expression/branch semantics;
root tests own public values, errors, ownership, and assembled behavior.
**Verify:** Run focused new contract tests and affected package tests, with **Verify:** Literal declared/undeclared input names, repeated references,
`-race` for the isolation tests. Reuse Stage 8 results for unchanged cases; required unused declarations, optional declarations/lookups, missing versus
commit. Avoid full-suite repetition solely to produce this commit. empty direct variables, root versus local references, and empty input-free
templates. Test unsupported-scope uncertainty, not assignment interpretation.
Run `go test ./internal/prompt ./internal/domain`; commit.
## Stage 10 — Document The Boundary And Verify The Assembled Feature ## Stage 3 — Classify Simple Branches And Inactive References
**Outcome:** Canonical documentation accurately describes the new capability, **Outcome:** Ordinary supplied-context branches give useful classifications;
and the complete feature is ready for review, not automatically published. inactive inputs and variables remain optional inventory.
**Work:** **Work:**
1. Finish GoDoc for every new public field, kind, issue category, method, 1. Add only the simple condition recognition in the scope table: direct values,
ownership/error behavior, and supported discovery boundary. State that literal-key lookups, literals, negation, and two-string equality/inequality.
inspection is not generation readiness or future-byte validation. Use Go truthiness; a supplied `"false"` string is truthy.
2. Add task-oriented consumer guidance comparing the three inspection methods 2. For `if`/`with`, collect the predicate's references under the parent's
and preparation. Demonstrate required `transcript`, missing variables, and reachability. Visit selected and skipped bodies with the appropriate
explicit incomplete discovery without a Promptkit JSON format. reachability and dot identity. In unresolved branches, mark accesses possible.
Explain optional inactive inventory and reading requirement classifications 3. Collect syntactically recognizable inactive input/caller names without
rather than treating every input entry as a binding to prepare. evaluating skipped expressions. Add inactive-only explanations; required
3. Update relevant format cross-references, internal source/runner/component declarations or other definite/possible uses take precedence.
documents, and development reading guidance. Do not duplicate the exact 4. Unknown/content-dependent conditions preserve known entries and limitations.
public contract outside GoDoc or describe unsupported constructs as invalid. An unresolved text-only branch need not be incomplete; dependency-bearing
4. Extend the maintained preparation example with a small inspection use before unresolved branches can remain incomplete without cross-branch proofs.
actual artifact preparation, preserving all existing example output 5. Do not add assignment environments, alias-value propagation, branch joins,
assertions. Verify the example's semantic inspection result locally without more comparison families, or short-circuit evaluation for complex conditions.
adding a second recurring release gate or replacing the other examples.
5. Check every roadmap acceptance outcome against implementation/tests. Confirm **Verify:** Known true/false branches, nested reachability, string truthiness,
the old inspection API/hash shapes and execution behavior are retained and simple comparisons, `with` dot versus explicit root, missing decision values,
no raw-source/history validation or new caller restriction was introduced. and content-dependent conditions. Include inactive literal input and caller
6. On final changed code, run one assembled offline verification using the references, promotion by active reuse, and declared required inputs.
selected local Go and prepared module caches: Confirm skipped unsupported/dynamic expressions do not introduce uncertainty
and an all-optional complete inventory needs no artifacts.
Compare a few supported cases with the real renderer.
Run `go test ./internal/prompt`; commit.
## Stage 4 — Resolve Direct Names And Finish Limitation Reporting
**Outcome:** Simple supplied names resolve exactly; complicated names and
constructs return useful partial inventories without speculative analysis.
**Work:**
1. Recognize the direct variable/lookup-derived helper names, simple
parentheses, and direct-to-input pipelines in the scope table.
Use a known string as an identifier without trimming or coercion.
2. Missing decision/name values, input-body dependence, unresolved helper
names, and dependency-relevant unsupported syntax produce the four issue
categories. Collect recognized references conservatively from unsupported
subtrees without executing functions, loops, or named calls.
3. Keep skipped computed input names unresolved without inventing an entry or
marking incompleteness from inactivity alone. The syntactically visible
caller key can still appear as an optional variable.
4. Finalize unknown-name/scope effects on affected optional entries using the
simple flags described above. Required declarations/definite accesses stay
required; uncertainty overrides misleading inactive-only explanations.
5. Finish independent result values and safe diagnostics. No possible-name
sets, underlying expression/value traces, placeholder names, or payload reads.
**Verify:** Exact direct names, optional literal-key lookups, empty versus
absent supplied names, and equivalent simple parenthesized/piped forms.
Use a few complex assignment/pipeline/range/named-call examples to prove
incomplete-success behavior, not broad interpretation coverage.
Check unresolved-name effects on optional entries and absent unrelated values
in results/explanations. Run `go test ./internal/prompt`; commit.
## Stage 5 — Wire Selection And The Public Facade
**Outcome:** Consumers can inspect a selected captured prompt before artifacts
exist, without execution collaborators or readiness checks.
**Work:**
1. Add `internal/usecase/requirements_inspection.go` and an internal request.
Check the nonblank prompt ID, use existing session normalization, honor
context cancellation, and select via `resolvePromptDefinition`.
2. Reuse request-profile/default-profile selection and
`resolveProfileSelection` for identity only. Share a small private selector
helper with preparation if needed, preserving its error identities/order.
3. Obtain the captured snapshot through the narrow repository capability and
invoke the analyzer. Missing required internal capability/snapshot is
operational `ErrPromptLoad`, not a successful partial result or source fallback.
4. Do not call preparation, target-completeness/credential checks, environment
lookups, artifact/schema readers, renderer, validator, admission, generation,
observations, or run-ID machinery.
5. Forward through `internal/engine` and add root `requirements.go` with the
planned values/method, conversion/copy helpers, GoDoc, and `mapPublicError`.
Nil engine follows `ErrInvalidConfig`. Operational errors return no result;
discovery limitations return an incomplete result and nil error.
6. Preserve public selection/session/cancellation error categories. Do not add
an error sentinel for incomplete discovery. Update internal runner/component
documents for the implemented method.
**Verify:** Focused selection tests cover explicit/default/partial profiles,
exact versions/ambiguity, direct-session bypass, cancellation, nil engine,
operational errors, and incomplete success. Use failing/counting execution
collaborators only to prove absence of the relevant effects.
Run affected use-case/engine tests and `go test ./...` for assembled facade
wiring; commit.
## Stage 6 — Protect Public Inventory And Ownership
**Outcome:** Public contract coverage protects the consumer need without
duplicating the syntax walker's detailed cases.
**Work:**
1. Add external-package `requirements_inspection_contract_test.go` with real
configured engines and minimal synthetic definitions.
2. Cover exact required `transcript`, undeclared literals, declaration metadata,
simple context-selected names, and inactive input/variable entries with safe
explanations. Missing required variables and complete discovery are separate.
3. Cover conditional/incomplete results and empty/all-optional complete
inventories. A direct session ID excludes its template-only inventory
entries; declarations/message references remain.
4. Prove inspection before artifacts exist and without credentials/schema
preparation/provider access. Use a valid partial profile and, where useful,
an explicit direct-key-required profile without its key.
5. Compare a small set of supported definite requirements with later preparation
using synthetic artifacts. Optional inactive inventory is not an executed
access; incomplete cases need not satisfy complete-analysis parity.
6. Verify captured file-backed content survives later file change/removal.
Mutate returned slices/metadata and repeat inspection; exercise simultaneous
inspections alongside preparation to protect captured-state ownership.
7. Check disclosure with marker values: unrelated variable values, direct
session values, template text, and credentials stay absent. Binding names,
caller keys, declared descriptions, and safe inactive explanations are allowed.
8. Root tests own public values/errors/assembled behavior; analyzer tests own
recognition/classification. Avoid duplicated interpretation matrices.
**Verify:** Run focused contract/affected package tests and `-race` for
ownership cases. Reuse unchanged prior checks rather than rerunning the full
suite solely for this unit; commit.
## Stage 7 — Document And Verify The Assembled Feature
**Outcome:** Implemented semantics and analysis limits are documented in their
canonical owners, with final verification ready for user review.
**Work:**
1. Finish GoDoc for classifications, presence, metadata, explanations, issues,
completeness, errors/ownership, and the deliberately small supported scope.
Complex valid templates may yield partial results; no authoring ban is added.
2. Update the consumer guide to compare the inspection APIs and preparation.
Show required input discovery, optional inactive input/variable inventory,
missing required variables, and explicit incomplete discovery.
3. Update relevant format cross-references and internal source/runner/component
documents. Keep exact implemented API contracts in GoDoc rather than copying
them into every guide.
4. Add a small inspection use to the maintained preparation example, preserving
its existing assertions. Verify it locally without adding another release gate.
5. Review roadmap acceptance against implementation/tests. Confirm no general
interpreter, stronger caller restriction, raw/intermediate configuration
validation, execution-readiness check, or speculative completeness promise
was introduced.
6. On final changed code, run one assembled offline verification using the local
Go installation and prepared module caches:
`go test -race -vet=off -mod=readonly -count=1 ./...`, `go test -race -vet=off -mod=readonly -count=1 ./...`,
`go vet -mod=readonly ./...`, and `go vet -mod=readonly ./...`, and
`python3 scripts/check-examples.py`. Set `GOTOOLCHAIN=local`, `GOWORK=off`, `python3 scripts/check-examples.py`. Set `GOTOOLCHAIN=local`, `GOWORK=off`,
`GOPROXY=off`, `GONOPROXY=none`, and `GOSUMDB=off`. `GOPROXY=off`, `GONOPROXY=none`, and `GOSUMDB=off`.
Check changed Go formatting, local documentation links, and `git diff --check`. Check changed Go formatting, local documentation links, and `git diff --check`.
There is no need to rerun release-tool publication fixtures for unchanged tools. Release-tool fixtures need not rerun when tooling is unchanged.
7. Record verification and implemented status in the temporary roadmap/plan 7. Record implemented status and verification in these temporary review
for user review. Do not tag, push, select a release version, write a prospective documents, commit, and report remaining limitations honestly. Release
release note, or retire the review artifacts in this implementation stage. preparation later owns version selection, notes, retirement, tags, and pushes.
Release preparation owns those later decisions.
8. Review the final change, commit the unit, and report remaining issues honestly.
Do not mark unsupported constructs complete merely to make tests pass.
## Completion Criteria ## Completion Criteria
- The root operation and dedicated public values implement the selected - The separate public operation returns input and caller-variable inventories
artifact-free, context-sensitive inspection contract. classified required, conditional, or optional for the selected context.
- Definitions/templates and required metadata presence come from the final - Recognizable inactive references remain optional entries in both inventories,
captured configuration; current inspection/execution and hashes remain intact. with safe explanations and aggregation that preserves stronger requirements.
- Practical-core complete results agree with execution semantics; uncertainty - Simple branches/direct names agree with execution; complex cases preserve
remains a structured successful partial result, not guessed absence or error. recognized names and explicit limitations without assignment/path solving.
- Missing values, conditional requirements, metadata absence, and session bypass - Effective metadata/captured templates come from final configuration and remain
are distinguishable without leaking unrelated content. immutable; existing inspection, hashes, and execution behavior remain intact.
- Inactive undeclared references appear as optional entries with explanations; - Selection, session bypass, missing versus empty caller keys, metadata presence,
they do not introduce skipped-variable requirements or uncertainty. Complete classification, and completeness have distinct documented meanings.
all-optional inventories remain distinguishable from incomplete discovery. - No artifacts, credentials, provider access, schemas, or execution state are
- Public classification and ownership tests pass; no provider/resource preflight, needed for inspection. Results preserve disclosure and public error boundaries.
arbitrary limit, application wire schema, or new template-validity rule was added. - Focused tests, the maintained example, canonical docs, and final assembled
- Canonical documentation and maintained examples reflect the implemented checks demonstrate the feature. No significant design questions remain open.
discovery boundary. Successful checks for the final snapshot are reported.

View File

@@ -1,273 +1,227 @@
# Effective Prompt Requirement Inspection # Effective Prompt Requirement Inspection
Status: Implementation planned; the feature is not implemented. The Status: Implementation planned; the feature is not implemented. The
[implementation plan](implementation.md) owns the ordered migration steps and [implementation plan](implementation.md) owns the ordered implementation steps.
implements the agreed analysis scope and inventory below. This document owns This document owns the purpose, scope, and target end state.
the target end state and migration scope.
## Purpose ## Purpose
Let consumers discover a selected prompt's caller requirements before its input Let consumers enumerate a selected prompt's inputs and caller variables before
artifacts exist. Scriptorium can expose that information to operators and to its input artifacts exist, with each name classified as required, conditional,
Narratio, which can compare its planned bindings with Promptkit's exact input or optional for the supplied context. Scriptorium can present that inventory
names before undertaking expensive pipeline work. 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 originating request is [Scriptorium's feature request](scriptorium-feature-request.md).
The capability is application-neutral: Promptkit describes prompt requirements; Promptkit supplies application-neutral inspection; consumers own presentation,
consumers interpret them for their own configuration, presentation, and workflow. binding checks, and their own workflows.
## Current Baseline ## Current Baseline
At review baseline `b595dca`: At review baseline `b595dca`:
- [InspectPrompt](../consumers/pkg-promptkit.md#inspect-a-prompt-before-preparation) - [InspectPrompt](../consumers/pkg-promptkit.md#inspect-a-prompt-before-preparation)
selects a captured prompt and reports declared inputs and output metadata. selects a captured prompt and reports declared inputs and output metadata,
It does not analyze templates or resolve the execution profile. without analyzing templates or resolving an execution profile.
- [InspectProfile](../consumers/pkg-promptkit.md#inspect-a-profile-before-prompt-work) - [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) - [Prepare](../consumers/pkg-promptkit.md#prepare-without-model-execution)
selects the execution context, checks target requirements, loads artifacts selects an execution context, loads artifacts and applicable schemas, and
and applicable schemas, and renders messages. It needs actual input data. renders messages. It needs actual input data.
- The configuration adapter captures final effective definitions, message - Engine construction captures final definitions and compiled message/session
contents, and compiled message/session templates during engine construction. templates. Rendering uses Go templates, string-valued caller variables, and
Runtime rendering uses Go templates, string-valued caller variables, and the the `input` helper. Required input declarations are checked independently of
`input` helper. Declared required inputs are checked independently of template branches; an executed helper also needs its named input.
branches; active helper calls also require their named inputs. - Declared content types and descriptions currently use string fields. The
- Declared input metadata currently uses string fields for content type and new inspection needs declaration information and effective metadata presence,
description. The new result needs to identify a declaration and distinguish including the difference between an absent field and an explicitly empty one.
available metadata from absent metadata, including effective presence where
necessary; current empty strings alone do not establish source-field presence.
The [format reference](../formats.md#messages-and-templates), The [format reference](../formats.md#messages-and-templates), existing GoDoc,
[internal source document](../internal/sources.md), and existing GoDoc own the and [internal source document](../internal/sources.md) own current behavior.
implemented semantics. No existing operation provides artifact-free,
context-sensitive requirement discovery.
## Target Public Operation ## Target Public Operation
Add a separate read-only engine operation, planned as Add `Engine.InspectRequirements` with dedicated public request/result values.
`Engine.InspectRequirements`, with a dedicated request and result. Preserve Preserve `InspectPrompt`, `InspectProfile`, preparation, and execution.
`InspectPrompt`, `InspectProfile`, preparation, and execution contracts.
The request supplies a prompt ID, optional version, optional profile selector, The request supplies a prompt ID, optional version and profile selectors,
supplied template variables, and an optional direct session ID. It needs no caller variables, and an optional direct session ID. It needs no artifact
artifact references or contents, output path, API key, or execution settings references or contents, output path, or credentials.
unrelated to discovery.
Selection follows equivalent execution semantics: exact identities, omitted Use execution's selection semantics: exact identities, omitted-version
version ambiguity, request profile or prompt default, and direct session-ID ambiguity, request profile or prompt default, and normalized direct session-ID
normalization and bypass. Return selected prompt ID/version and effective bypass. Report the selected prompt ID/version and effective profile ID.
profile ID. Profile selection establishes identity, not generation readiness; Selecting a profile establishes identity, not generation readiness; partial
profiles that depend on later execution overrides need not be completed here. profiles remain inspectable.
Use the configured engine's captured definitions. Source discovery and layering Use the configured engine's captured definitions. Source selection remains a
remain consumer choices. Results describe that captured context, not a promise consumer choice. Results describe that captured context, not a later engine or
about a later engine or later execution with changed variables. execution with different variables.
## Result And Requirement Meanings ## Result And Classification
Expose public Go values with documented classifications and predictable ordering. Return an inventory of inputs and a separate inventory of caller variables.
Exact symbol and field spelling belongs in the implementation plan Each entry has one of three requirement classifications:
and GoDoc. No Promptkit JSON wire schema is part of this feature.
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. A required declaration stays required even in an inactive branch. A definite
- Known input names, preserving execution identity, with required, optional, helper use promotes an optional input declaration to required. Aggregate repeated
or conditional classification for the supplied context. occurrences by exact name: required takes precedence over conditional, which
- Declaration information, descriptions, and content-type metadata where takes precedence over optional. Conservative conditional classification is
available. A template-discovered undeclared input must not look like a acceptable where analysis cannot establish necessity; inspection need not prove
declared input with known metadata. Report existing media-type metadata, equivalence between alternative execution paths.
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.
Required means the caller must supply the input for this context. A declared Input entries distinguish declarations from discovered undeclared references
required input stays required even if no active template references it. A and preserve available descriptions/content types. They do not infer input
declared optional input becomes required when an active template use needs it. schemas or introduce format enforcement. Variables identify caller-map keys,
Optional means it is known not to be required for this context; conditional not template-local symbol names, and report whether each key was supplied.
means its requirement depends on unresolved context. Do not use optional to An empty supplied string is present; absence is separate from classification.
hide uncertainty. Known required declarations retain that classification even
when other requirements are conditional or undiscoverable.
Include statically identifiable undeclared references on known inactive paths Include recognizable references on known inactive paths in both inventories
as optional entries with an inactive-use explanation. A required or conditional as optional entries with an inactive-use explanation. Keep explanations separate
use elsewhere takes precedence over that inactive-only classification and from declared input descriptions. An applicable required or conditional use
explanation. Inactivity itself is not discovery uncertainty. 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 Deduplicate names and provide predictable ordering. Results also identify the
absence from recognized active uses alone does not establish that it is selected context and provide discovery completeness with machine-readable
definitely optional; classification and uncertainty must account for that limitation categories and safe explanations. Exact public spellings belong in
possibility. 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 ## Simple Discovery Boundary
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.
Completeness describes discovery, not readiness or satisfaction. For example, Use parsed template syntax, not raw-text matching or rendering with placeholder
a missing variable used only to insert text can be a known unsatisfied artifacts. The intended algorithm is straightforward:
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.
## 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 The source inventory is finite and ordinarily small. Direct traversal and
placeholder artifacts. Use supplied variable values where they determine name-indexed aggregation are sufficient; no size caps, analysis budgets,
branches and input names, following execution's presence, truthiness, scope, branch-combination enumeration, or global analysis cache are needed.
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.
Include dependencies from messages and the applicable session-ID template. Recognize literal input names, direct caller-variable access, literal-key root
A direct nonblank session ID bypasses that template, removing only requirements lookups, direct variable-derived input names, and ordinary `if`/`with` branches.
introduced solely by it; declarations and message uses remain relevant. Use simple truthiness, negation, and equality/inequality where straightforward.
The bypassed session template is also excluded from the inactive inventory. 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 Retain enough lexical/dot scope awareness to distinguish caller variables from
undeclared references. Artifact content being unavailable does not by itself locals. Complicated assignments, pipelines, computed names, ranges, or invoked
make discovery incomplete: it does so when the content affects which further named templates can remain outside complete analysis. Preserve identifiable
requirements apply. Variable-derived names are discoverable when supported references and report limitations rather than implementing a general template
analysis can determine the exact name from the supplied context. 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 On a known inactive path, collect names visible in syntax without evaluating
analysis limitations prevent determination, preserve known requirements and its expressions. Literal input names and recognizable caller keys remain in
return successful incomplete discovery. Structured reasons should distinguish the inventory; skipped dynamic input names need not be resolved. Unsupported
these situations without requiring diagnostic-text matching. Unsupported skipped expressions do not themselves make discovery incomplete.
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.
The selected practical analysis core and inactive inventory are described below. A direct nonblank session ID excludes the bypassed session template from both
They do not change execution or expand the template language. 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 ## Effects, Errors, And Disclosure
Inspection uses captured prompt resources and needs no future artifact files, Inspection uses captured resources without future artifact reads, schema
credential lookup, model access, capacity admission, or execution artifact preparation, credential lookup, model calls, capacity admission, observations,
creation. It does not prepare an output-validation schema or validate future run IDs, or execution artifact creation. Necessary configuration/resource
input bytes. Necessary configuration/resource failures can still prevent engine failures can still prevent engine construction or inspection.
construction or inspection; this is not a general resource preflight.
Use existing public selection/error identities wherever applicable, including Preserve publicly classifiable selection errors and ordinary context
invalid requests, missing prompt/profile selections, and ambiguous versions. cancellation. Discovery uncertainty is a successful result, not an operational
Preserve ordinary context cancellation behavior. Discovery uncertainty is a error or a new definition-validity rule. A complete result does not promise
result state, distinct from an operational or selection error. Expose any successful rendering, generation, future artifact validity, or provider
additional necessary classifications through the public facade, not diagnostic availability.
text parsing or internal types.
Results and safe diagnostics exclude credential values, artifact payloads, Results and diagnostics exclude credential values, artifact payloads,
raw/rendered prompt content, and unrelated supplied variable values. Selected raw/rendered prompt content, and unrelated supplied values. Selected identities,
identities, input/variable names, and declared descriptions are intentional input/variable names, and declared descriptions are intentional operator
operator metadata. A resolved dynamic input identifier may equal a supplied metadata. A directly resolved input identifier may equal a supplied variable
variable value; reporting that identifier is necessary to describe the binding. value; reporting that binding name is necessary, without echoing its originating
Keep the disclosure exception limited to its role as an identifier, without expression or variable map.
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.
## Work Needed From The Baseline ## Work Needed From The Baseline
Add public request/result values and the engine method through the existing Add request/result values and the engine method through the root facade.
facade. Put selection coordination and analysis in internal components with Keep selection coordination internal and place syntax discovery with the
cohesive ownership. Reuse existing prompt/profile selection, session override, existing prompt-template component. Reuse captured templates and selection
and template parsing semantics rather than introducing a second preparation helpers rather than creating another preparation path.
path or a general-purpose template interpreter.
Make the captured templates and effective declaration metadata available to Capture required metadata presence at the final ConfigKit handoff and retain it
internal inspection. Retain any required metadata presence at the ConfigKit alongside inspection snapshots. Apply [ADR 0001](../adr/0001-configuration-boundary.md):
handoff. Apply [ADR 0001](../adr/0001-configuration-boundary.md): inspection interpret final effective definitions, not raw/intermediate configuration or
interprets final effective definitions, not raw sources, configuration history, history. Operator provenance remains a separate explicit API.
or intermediate artifacts. Operator provenance remains a separate explicit API.
Implement requirement aggregation, context-sensitive analysis, and safe public Implement a small syntax walker, simple context tests, classification
uncertainty/error conversion. Keep request-specific analysis separate from aggregation, and safe limitation reporting. Keep request-specific state separate
shared captured state. Prefer direct traversals and indexed aggregation; avoid from captured definitions. Focus tests on representative enumeration,
enumerating every possible branch combination or repeated full-template scans. classifications, scope mistakes, selection, capture/ownership, and absence of
Predictable result ordering does not require a stronger complexity guarantee execution effects, under the [testing policy](../policy/testing.md). Do not test
or a new global cache. a general interpreter or repeat ConfigKit's source-loading matrix.
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.
When implementation lands, update GoDoc, the consumer guide, relevant format When implementation lands, update GoDoc, the consumer guide, relevant format
cross-references, and the internal component/source documents. Describe the cross-references, internal documents, and a maintained example. Canonical owners
analysis boundary and examples of complete, unsatisfied, and incomplete results document the implemented boundary; release notes summarize rather than own it.
in their canonical owners. Release notes explain the new capability; they do
not own its contract. The implementation plan owns implementation sequencing.
## Acceptance Outcomes ## Acceptance Outcomes
- A required `transcript` is reported exactly, allowing a consumer to detect a - Required `transcript` is reported exactly before its artifact exists.
planned binding under the wrong name before the transcript exists. - Literal undeclared helper names are discoverable without definition rejection.
- Literal undeclared helper references are discoverable without making their - Input and variable references are classified as required, conditional, or
absence from declarations a new definition error. optional, including recognizable inactive references in both inventories.
- Declared required inputs remain required in inactive branches; optional - Required declarations stay required; definite uses promote optional entries;
declarations remain optional where no applicable use makes them required. other occurrences never erase an established required use.
- Statically identifiable inactive undeclared references are optional entries - Simple supplied-context branches and direct dynamic names follow execution;
with an inactive-use explanation; active and unresolved uses of the same name complicated or content-dependent cases preserve known entries and limitations.
take precedence. These entries do not introduce variable requirements or - Caller keys remain distinct from template locals, and supplied empty values
incompleteness solely from skipped expressions. remain distinct from absent keys.
- Supported variable-dependent branches and names agree with execution; - Selection and session bypass follow execution without readiness checks.
unresolved content/name/analysis cases retain known entries and uncertainty. - Complete artifact-free inventories remain distinguishable from empty partial
- Version/profile/default selection and session-template bypass agree with discovery; completeness remains separate from supplied-variable presence.
execution without credential or generation-readiness checks. - Results/errors preserve the disclosure and public classification boundaries.
- Variables are reported separately, with absent and empty supplied values - Existing inspection/execution contracts remain intact. Application APIs,
interpreted according to the existing template semantics. pipeline planning, binding validation, presentation, provider preflight, input
- Artifact-free complete results, including all-optional inventories, are schemas, and a general-purpose template evaluator remain outside this scope.
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.