diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 10d39d6..d54c53b 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,55 +1,46 @@ # Effective Prompt Requirement Inspection Implementation Plan -Implement the [feature roadmap](inspection.md) in order. Each numbered stage -is scoped for one Luna coding-agent prompt. This plan replaces the completed -ReleaseKit adoption plan; that plan remains available in Git history. +Implement the [feature roadmap](inspection.md) in order. Each numbered stage is +scoped for one Luna coding-agent prompt. This plan replaces the earlier +interpreter-style analysis scope with simple enumeration and conservative +classification. The completed ReleaseKit plan remains available in Git history. ## Baseline And Working Rules -- Baseline: `7827ca043b5de84a18199ac8f4b3056691aacbb5`. There is no effective - requirement-inspection API yet. `InspectPrompt` reports declarations; - `Prepare` needs artifacts. The configured engine captures compiled templates. -- The agreed scope is the practical analysis core, with statically identifiable - 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 +- Planning baseline: `e459c7d`. The inspection API is not implemented. + `InspectPrompt` reports declarations, `Prepare` needs artifacts, and the + configured engine already captures compiled templates. +- Start with [development](../development.md), then the [agent](../policy/agents.md), [architecture](../policy/architecture.md), [testing](../policy/testing.md), and [documentation](../policy/documentation.md) - policies. Reuse unchanged policies already read. Follow - [ADR 0001](../adr/0001-configuration-boundary.md): interpret final effective - configuration at the ConfigKit handoff, never raw/intermediate sources or - configuration history. -- Inspect the current worktree before each stage; preserve unrelated work. - Validate and commit each completed unit under the agent policy. Keep current - internal documentation accurate as each internal capability lands. -- Preserve all existing inspection, construction, preparation, rendering, and - execution contracts. Discovery limitations must not invalidate templates. - Do not add variable defaults, input schemas, name restrictions, count/size - limits, a branch-expansion budget, or generation-readiness checks. -- No provider calls, actual publication, new dependency, CLI/HTTP layer, upstream - ConfigKit change, or application-specific pipeline concept is needed. -- Public declarations belong in the root facade; analysis belongs in - `internal/prompt`, selection coordination in `internal/usecase`, and metadata - capture in `internal/configuration`. Runtime/domain values remain independent - of ConfigKit. Use the standard parser and `template.IsTrue`; do not implement - a replacement template language or execute whole prompts with fake artifacts. + policies. Reuse unchanged policies already read. +- Follow [ADR 0001](../adr/0001-configuration-boundary.md): interpret only final + effective configuration at the ConfigKit handoff. Operator provenance is + separate; inspection does not examine raw sources or intermediate values. +- Preserve unrelated work and commit completed, verified units under the agent + policy. Keep implemented internal documentation accurate as stages land. +- Preserve existing construction, inspection, preparation, rendering, and + execution contracts. An inspection limitation is not a definition error. +- Use captured parsed syntax, direct traversal, and maps keyed by exact name. + No general evaluator, assignment-value propagation, branch-environment joins, + possible-name sets, branch combinations, analysis budget, or global cache is + needed. Do not add caller limits, defaults, input schemas, or authoring bans. +- The root package owns public declarations/conversion. `internal/prompt` + owns discovery, `internal/usecase` coordinates selection, and + `internal/configuration` supplies captured syntax/metadata. Runtime/domain + values remain independent of ConfigKit. +- No new dependency, upstream ConfigKit change, provider access, CLI/HTTP + 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 func (e *Engine) InspectRequirements( ctx context.Context, req RequirementInspectionRequest, ) (*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 { PromptID string PromptVersion string @@ -58,7 +49,7 @@ type RequirementInspectionRequest struct { SessionID string } -type RequirementKind string // constants: required, optional, conditional +type RequirementKind string // values: required, conditional, optional type InputRequirement struct { Name string @@ -70,9 +61,10 @@ type InputRequirement struct { } type VariableRequirement struct { - Name string - Kind RequirementKind - Supplied bool + Name string + Kind RequirementKind + Supplied bool + Explanation string } type RequirementIssueCode string @@ -95,495 +87,355 @@ type RequirementInspection struct { } ``` -Use `RequirementRequired`, `RequirementOptional`, and -`RequirementConditional` as the kind constant names. Use these issue constants: +Use root-owned values and internal counterparts in +`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. | -| `RequirementIssueInputContent` | `input_content` | Unavailable artifact content affects further dependencies. | -| `RequirementIssueDynamicInputName` | `dynamic_input_name` | A helper's exact selected name remains unresolved. | -| `RequirementIssueUnsupportedConstruct` | `unsupported_construct` | A construct outside the analysis core prevents discovery. | -| `RequirementIssueExpressionUnresolved` | `expression_unresolved` | An expression cannot be evaluated within the supported semantics, including an incompatible operation. | +| `RequirementIssueMissingVariable` | `missing_variable` | An absent value prevents determining a dependency decision/name. | +| `RequirementIssueInputContent` | `input_content` | Unavailable artifact content affects dependencies. | +| `RequirementIssueDynamicInputName` | `dynamic_input_name` | A referenced input name cannot be determined. | +| `RequirementIssueUnsupportedConstruct` | `unsupported_construct` | Analysis does not cover a dependency-relevant expression or scope. | -Use safe, fixed-category descriptions, optionally identifying reported names. -Do not expose the expression, its literals unrelated to identifiers, its -evaluated values, raw template text, or a Go template execution error. An empty -associated name means no particular named entry is identified; it does not -establish that an input/variable is absent. +An empty associated name means that no particular entry was identified. +Descriptions and explanations are safe human-readable summaries, not strings +callers must parse. There is no expression tree, source offset, JSON tag/schema, +or stable diagnostic wording contract. -### Classification, Metadata, And Ownership +### Classification And Ownership -- Always report declarations. A declared required input stays required. - Active template accesses can promote an optional declaration to required. - Include statically identifiable undeclared references on known inactive paths - as optional entries with an inactive-use explanation. -- An entry is required when its use is established for the context, conditional - when a possible use depends on unresolved analysis, and optional when no - applicable use needs it and unresolved effects do not undermine that conclusion. - An established required use dominates conditional/optional uses. -- `Explanation` is a safe human-readable summary of inactive-only use, separate - from declared `Description`. Its wording is not a machine-readable contract. - Do not add an uncertainty issue for known inactivity. Required or conditional - uses elsewhere override inactive-only classification and explanation. - Caller variables used solely on known inactive paths are not requirements. -- Aggregate inputs and variables by exact execution name. Do not trim request - variable keys or discovered helper names. Configuration normalization remains - with the existing configuration adapter. -- Metadata pointers distinguish absent/cleared metadata from an explicit - value, including an explicitly empty value. `Declared` distinguishes a known - declaration from a helper-only reference. No new input-format enforcement. -- `Supplied` is key presence in the caller's variable map, including an empty - string. A required variable's presence satisfies that known presence - requirement; a conditional variable's necessity is unresolved. Optional - lookup absence is not a missing required value. Do not infer Boolean values, - nonblank constraints, or other variable validation from names. -- Sort inputs and variables lexicographically by exact name. Deduplicate issues - by code/input-name/variable-name and sort by that tuple. Diagnostics need no - 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. +- Seed declared inputs from final effective definitions. Required declarations + stay required independently of syntax. Others start optional. +- Collect occurrences with definite, possible, or inactive reachability. + Definite helper/direct required-variable accesses are required; possible ones + are conditional; recognizable inactive references are optional. A lookup + that execution permits to be absent remains optional unless another access + establishes a stronger requirement. +- Aggregate exact names with required > conditional > optional. No proof that + a name in both unresolved branches is required is necessary: conditional is + acceptable until an independent definite access/declaration establishes it. +- Include recognizable inactive inputs and caller variables in both inventories. + Give inactive-only entries an `Explanation`, independent of declared input + `Description`. Any applicable occurrence, including an optional lookup, + removes the inactive-only explanation; required/conditional uses also + override optional classification. Inactivity is not an uncertainty issue. +- Input metadata pointers distinguish absence/null from an explicit string, + including an empty string. `Declared` distinguishes metadata ownership from + a helper-only reference. Do not infer new input formats. +- `Supplied` means presence of the exact caller key, including empty strings. + It is independent of classification and completeness; do not echo values. +- Sort input and variable entries lexically by exact name. Deduplicate issues + by code/input-name/variable-name and sort by that tuple. Do not promise a + nil-versus-empty slice distinction. +- Return independent slices and metadata pointers, copy request variables at + the facade as for `RunRequest`, and keep captured syntax immutable. Retain + callers' existing responsibility for concurrently mutating requests. -### Completeness And Uncertainty +### Deliberately Small Recognition Scope -`Complete` concerns discovery of both input and variable requirements, not -whether they are satisfied. `{{.audience}} {{input "note"}}` can yield complete -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. +Use the standard template parse tree and `template.IsTrue` for known values. +Only determine a value when needed for a recognized name or simple condition. -Unknown values carry their cause internally. Emit issues and mark incomplete -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 | +| Syntax | Initial handling | | --- | --- | -| Text/comments and sequences | No text output; visit executable actions in order. | -| String, Boolean, nil literals; dot/root | Track known values needed for dependencies; root is the supplied string map. | -| Root-map field access, including `$.name` | Record a required named caller variable; absent key produces an unknown value, not an inspection error. | -| Dot inside `with` | Follow the selected pipeline value; do not reinterpret string fields as caller root keys. | -| `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. | -| Local variables | Single-variable declarations and assignments, root `$`, aliases, lexical scope, and pipeline results; locals are not caller variables. | -| `input` | Known string names, including direct variable/alias-derived names; record the dependency and return an unknown body value. | -| Pipelines/parenthesized expressions | Respect argument order and the previous value's final-argument position. | -| `and`, `or`, `not` | Go truthiness and short-circuit access semantics; return Go-compatible operand/Boolean values. | -| `eq`, `ne`, `lt`, `le`, `gt`, `ge` | String comparisons, including `eq`'s multiple comparison operands; all ordinary arguments are evaluated as Go does. | -| `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. | +| Literal `input "name"` | Collect the exact name without reading its body. Parenthesized literal wrappers and a literal piped directly to `input` are equivalent. | +| Direct root `.name` or `$.name` | Collect a required caller key when active; supplied strings are known, absence is unresolved rather than 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. | +| `input .name`, `input $.name`, or `input (index . "name")` | Resolve a directly available string as an input identifier on applicable paths. | +| One simple value piped directly to `input`, or parenthesized simple expressions | Recognize the same bounded forms without evaluating arbitrary pipelines. | +| String/Boolean/nil literals and simple direct values | Use known values for conditions; no coercion of caller strings. | +| `not` of a simple predicate; two-string `eq`/`ne` | Recognize negation and ordinary equality/inequality without adding the full comparison family. | +| `if`/`else`, `with` | Classify branch occurrences using a recognized condition; unresolved branches are possible, not guesses. | +| 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. | +| 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. | -A numeric literal or unsupported pure output expression is not itself a caller -requirement. Discover its evaluated arguments where that is safe; its value can -remain unknown until a later dependency decision needs it. Known short-circuit -paths must not collect dependencies from skipped operands or branches. -They can contribute optional inactive inventory as described below, without -collecting skipped caller-variable requirements or uncertainty. +An unsupported expression does not automatically make every argument a definite +access: short-circuiting or unknown scopes can make references merely possible. +Keep complex forms outside complete analysis instead of emulating their rules. +Do not interpret `$local` as a caller key or `.field` on a string/unknown dot as +a root lookup. Explicit root accesses remain recognizable only while the root +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 -`input` names, including equivalent parenthesized/piped literal forms. Walk -skipped branch bodies and short-circuit operands without reading caller values, -mutating local environments, or invoking templates/functions. Unresolved -dynamic names and unsupported expressions in these skipped paths do not make -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. +Walk known inactive subtrees for syntactically identifiable literal input names +and caller keys. Do not evaluate skipped expressions, resolve skipped dynamic +input names, or produce uncertainty solely from skipped constructs. Names +hidden behind unsupported scopes need not be invented. Exclude bypassed session +templates and never-invoked definitions entirely. -Use a small private known/unknown value model. Branch joins retain identical -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. +### Simple Algorithm And Completeness -## 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 -changing execution definitions, hashes, or existing public inspection values. +Use shared traversal helpers for active/possible/inactive syntax rather than +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`, `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:** -1. Add internal metadata/snapshot values. Retain content-type/description - presence alongside `promptEntry`, not inside the JSON-hashed - `domain.PromptDefinition` or the existing public `PromptInputDefinition`. +1. Retain content-type/description presence alongside configuration + `promptEntry`, rather than changing the hashed prompt definition or old + public inspection shape. 2. Capture effective per-input presence from `Resolution.InputInfo` during the - existing Resolve callback before `resolvePrompts` can record normalized - sequences. Use final prompt-ID/version/input-index paths only, following the - existing backend/profile presence-capture pattern. Do not inspect history. -3. Materialize metadata values from the normalized final declaration. Treat - absent/null as no metadata and an explicit empty string as available metadata; - preserve existing accepted/rejected configuration semantics. -4. Define `prompt.RequirementSnapshot` containing compiled templates and - declaration metadata, plus the narrow internal lookup - `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. + existing Resolve callback before prompt normalization. Use final + prompt-ID/version/input-index paths, following the existing presence-capture + pattern. Materialize values from the normalized final declaration. +3. Add `prompt.RequirementSnapshot` with captured templates and metadata, and + narrow internal `GetRequirementSnapshot(id, version string) + (RequirementSnapshot, bool)` access on the captured configuration adapter. + Use selected exact keys, without reparsing or reopening resources. +4. Preserve renderer/constructor paths and update internal source documentation. -**Verify:** Focused configuration tests cover absent, empty, nonempty, and -normalization-sensitive metadata, with real final-value layering/resource capture. -Confirm old inspection shape and definition hashes remain unchanged for equivalent -existing definitions. 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; +**Verify:** Focused final-value metadata tests for absent/null, empty, and +nonempty values, plus equivalent-definition hashes and old inspection behavior. +Use actual configuration capture rather than another source-loading matrix. +Run `go test ./internal/configuration ./internal/promptdef ./internal/prompt`; 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 -duplicating the analyzer's detailed case matrix. +**Outcome:** An internal syntax walker produces deduplicated inventories and +does not confuse caller variables with template locals. **Work:** -1. Add external-package `requirements_inspection_contract_test.go` using real - configured engines and minimal synthetic definitions. Use the existing - mapping/profile helpers, not a downstream checkout. -2. Prove exact `transcript` discovery, undeclared literal inputs, required and - optional declarations in inactive branches, context-selected names, and - session-only requirements removed by a direct session ID. - Include optional inactive undeclared entries with explanations, active reuse - overriding inactivity, and bypassed session names absent from the inventory. -3. Cover complete-but-unsatisfied variable requirements, conditional/unknown - dependencies, and empty complete versus empty incomplete input sets. - Cover complete all-optional inventories and no caller requirements from - solely inactive variable accesses. -4. Preserve classifiable errors for selection/cancellation. Test inspection - against a valid partial profile and an explicit direct-key-required profile - without an API key; missing runtime schemas and future artifact files must - 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. +1. Add internal result counterparts in `internal/domain/requirements.go` and + an analyzer entry in `internal/prompt/requirements.go`, taking context, + selected definition/snapshot, supplied variables, and session bypass. +2. Seed declarations, visit executable message roots and the applicable session + root, and collect literal input references and direct/literal-index caller + keys. Exclude uncalled definitions and a bypassed session template. +3. Implement aggregation, exact names, supplied-key presence, independent + metadata, sorting, and safe issues/explanations. Add ordinary traversal + cancellation checks without stronger interruption promises or workers. +4. Track scope identity, not local values: root-map versus nonroot/unknown dot + and local bindings. For unsupported scope changes, keep safely recognizable + references and report incomplete analysis rather than inventing caller keys. +5. Until Stage 3, classify branch references conservatively as possible and + unsupported dependency-bearing expressions as limitations. +6. Update the implemented internal component/source descriptions. -**Verify:** Run focused new contract tests and affected package tests, with -`-race` for the isolation tests. Reuse Stage 8 results for unchanged cases; -commit. Avoid full-suite repetition solely to produce this commit. +**Verify:** Literal declared/undeclared input names, repeated references, +required unused declarations, optional declarations/lookups, missing versus +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, -and the complete feature is ready for review, not automatically published. +**Outcome:** Ordinary supplied-context branches give useful classifications; +inactive inputs and variables remain optional inventory. **Work:** -1. Finish GoDoc for every new public field, kind, issue category, method, - ownership/error behavior, and supported discovery boundary. State that - inspection is not generation readiness or future-byte validation. -2. Add task-oriented consumer guidance comparing the three inspection methods - and preparation. Demonstrate required `transcript`, missing variables, and - explicit incomplete discovery without a Promptkit JSON format. - Explain optional inactive inventory and reading requirement classifications - rather than treating every input entry as a binding to prepare. -3. Update relevant format cross-references, internal source/runner/component - documents, and development reading guidance. Do not duplicate the exact - public contract outside GoDoc or describe unsupported constructs as invalid. -4. Extend the maintained preparation example with a small inspection use before - actual artifact preparation, preserving all existing example output - assertions. Verify the example's semantic inspection result locally without - adding a second recurring release gate or replacing the other examples. -5. Check every roadmap acceptance outcome against implementation/tests. Confirm - the old inspection API/hash shapes and execution behavior are retained and - no raw-source/history validation or new caller restriction was introduced. -6. On final changed code, run one assembled offline verification using the - selected local Go and prepared module caches: +1. Add only the simple condition recognition in the scope table: direct values, + literal-key lookups, literals, negation, and two-string equality/inequality. + Use Go truthiness; a supplied `"false"` string is truthy. +2. For `if`/`with`, collect the predicate's references under the parent's + reachability. Visit selected and skipped bodies with the appropriate + reachability and dot identity. In unresolved branches, mark accesses possible. +3. Collect syntactically recognizable inactive input/caller names without + evaluating skipped expressions. Add inactive-only explanations; required + declarations or other definite/possible uses take precedence. +4. Unknown/content-dependent conditions preserve known entries and limitations. + An unresolved text-only branch need not be incomplete; dependency-bearing + unresolved branches can remain incomplete without cross-branch proofs. +5. Do not add assignment environments, alias-value propagation, branch joins, + more comparison families, or short-circuit evaluation for complex conditions. + +**Verify:** Known true/false branches, nested reachability, string truthiness, +simple comparisons, `with` dot versus explicit root, missing decision values, +and content-dependent conditions. Include inactive literal input and caller +references, promotion by active reuse, and declared required inputs. +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 vet -mod=readonly ./...`, and `python3 scripts/check-examples.py`. Set `GOTOOLCHAIN=local`, `GOWORK=off`, `GOPROXY=off`, `GONOPROXY=none`, and `GOSUMDB=off`. Check changed Go formatting, local documentation links, and `git diff --check`. - There is no need to rerun release-tool publication fixtures for unchanged tools. -7. Record verification and implemented status in the temporary roadmap/plan - for user review. Do not tag, push, select a release version, write a prospective - release note, or retire the review artifacts in this implementation stage. - 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. + Release-tool fixtures need not rerun when tooling is unchanged. +7. Record implemented status and verification in these temporary review + documents, commit, and report remaining limitations honestly. Release + preparation later owns version selection, notes, retirement, tags, and pushes. ## Completion Criteria -- The root operation and dedicated public values implement the selected - artifact-free, context-sensitive inspection contract. -- Definitions/templates and required metadata presence come from the final - captured configuration; current inspection/execution and hashes remain intact. -- Practical-core complete results agree with execution semantics; uncertainty - remains a structured successful partial result, not guessed absence or error. -- Missing values, conditional requirements, metadata absence, and session bypass - are distinguishable without leaking unrelated content. -- Inactive undeclared references appear as optional entries with explanations; - they do not introduce skipped-variable requirements or uncertainty. Complete - all-optional inventories remain distinguishable from incomplete discovery. -- Public classification and ownership tests pass; no provider/resource preflight, - arbitrary limit, application wire schema, or new template-validity rule was added. -- Canonical documentation and maintained examples reflect the implemented - discovery boundary. Successful checks for the final snapshot are reported. +- The separate public operation returns input and caller-variable inventories + classified required, conditional, or optional for the selected context. +- Recognizable inactive references remain optional entries in both inventories, + with safe explanations and aggregation that preserves stronger requirements. +- Simple branches/direct names agree with execution; complex cases preserve + recognized names and explicit limitations without assignment/path solving. +- Effective metadata/captured templates come from final configuration and remain + immutable; existing inspection, hashes, and execution behavior remain intact. +- Selection, session bypass, missing versus empty caller keys, metadata presence, + classification, and completeness have distinct documented meanings. +- No artifacts, credentials, provider access, schemas, or execution state are + needed for inspection. Results preserve disclosure and public error boundaries. +- Focused tests, the maintained example, canonical docs, and final assembled + checks demonstrate the feature. No significant design questions remain open. diff --git a/docs/roadmap/inspection.md b/docs/roadmap/inspection.md index 2250abf..70ce6b0 100644 --- a/docs/roadmap/inspection.md +++ b/docs/roadmap/inspection.md @@ -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.