Avoid rescanning unsupported input names
This commit is contained in:
@@ -80,6 +80,8 @@ entries are reported as conditional rather than inactive-only or definitively
|
||||
optional. Direct root-map `with` forms retain caller-map identity. Known scalar
|
||||
values remain separate from unknown scopes; accesses through untracked local
|
||||
maps report incomplete discovery rather than silently losing caller keys.
|
||||
Unsupported name expressions reuse value analysis's conservative syntax scan
|
||||
instead of recursively rescanning the same subtree.
|
||||
Invoked named templates are scanned conservatively, and
|
||||
dependency-bearing range scopes make discovery incomplete. Uncalled definitions
|
||||
and bypassed session templates are not traversed. This internal walker does not
|
||||
|
||||
@@ -56,6 +56,11 @@ discovery. Retain known-string dot isolation and inactive-path behavior.
|
||||
|
||||
### Finding 2 — Avoid Recursive Rescanning Of Unsupported Names (P2)
|
||||
|
||||
**Status: Resolved.** The duplicate fallback traversal was removed. A focused
|
||||
source-relative work regression failed before the fix (4,096 accesses for a
|
||||
277-byte expression) and passed afterward, preserving partial-result metadata.
|
||||
No production limits or caches were added; prompt/use-case race tests passed.
|
||||
|
||||
Location: [requirement walker](../../internal/prompt/requirements.go),
|
||||
`evaluateInputName` (lines 231–244), through `evaluateValue`,
|
||||
`evaluateCommand`, and `visitCommand`.
|
||||
|
||||
@@ -253,11 +253,9 @@ func (walker *requirementWalker) evaluateInputName(node parse.Node, reach requir
|
||||
}
|
||||
evaluation.unsupported = true
|
||||
}
|
||||
if evaluation.unsupported {
|
||||
// Preserve directly recognizable references from a computed name without
|
||||
// treating the computation itself as an evaluated dependency.
|
||||
_ = walker.visit(node, requirementPossible, dot)
|
||||
}
|
||||
// Value analysis has already visited recognizable references, including
|
||||
// the conservative fallback for unsupported expressions. Do not rescan
|
||||
// the same subtree: nested computed names would multiply that work.
|
||||
return walker.unresolvedInputName(evaluation)
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,35 @@ func TestAnalyzeRequirementsUnknownScopesAffectOptionalEntriesOnlyWhenActive(t *
|
||||
}
|
||||
}
|
||||
|
||||
func TestRequirementWalkerDoesNotRescanNestedUnsupportedNames(t *testing.T) {
|
||||
for _, depth := range []int{6, 12} {
|
||||
expression := ".selector"
|
||||
for level := 0; level < depth; level++ {
|
||||
expression = `input (printf "%s" (` + expression + `))`
|
||||
}
|
||||
source := "{{" + expression + "}}"
|
||||
compiled := compileRequirementTemplate(t, "computed-name", source)
|
||||
walker := &requirementWalker{
|
||||
ctx: context.Background(), vars: map[string]string{"selector": "binding"},
|
||||
inputs: make(map[string]*inputEvidence), variables: make(map[string]*variableEvidence),
|
||||
issues: make(map[requirementIssueKey]domain.RequirementIssue), complete: true, rootKnown: true,
|
||||
}
|
||||
if err := walker.walkTemplate(compiled); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// A generous source-relative bound detects exponential rescanning, not
|
||||
// an exact visit count or a production analysis limit.
|
||||
if walker.dependencies > len(source)*8 {
|
||||
t.Fatalf("depth=%d: %d accesses for %d bytes of source", depth, walker.dependencies, len(source))
|
||||
}
|
||||
result := walker.result(domain.RequirementInspection{})
|
||||
if result.Complete || len(result.Variables) != 1 || result.Variables[0].Name != "selector" ||
|
||||
result.Variables[0].Kind != domain.RequirementConditional || len(result.Issues) == 0 {
|
||||
t.Fatalf("nested unsupported names lost discovery metadata: %+v", result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAnalyzeRequirementsCollectsDeclaredAndLiteralInputs(t *testing.T) {
|
||||
description := "retained metadata"
|
||||
definition := &domain.PromptDefinition{ID: "capture", Version: "v1"}
|
||||
|
||||
Reference in New Issue
Block a user