Merge condition evidence without repeated copies
This commit is contained in:
@@ -444,6 +444,12 @@ rendering comparisons. Source work counts or focused measurements demonstrate
|
|||||||
removal of the identified growing-copy pattern; no grammar or expression limit
|
removal of the identified growing-copy pattern; no grammar or expression limit
|
||||||
changes, universal complexity promise, or allocation-count assertion is added.
|
changes, universal complexity promise, or allocation-count assertion is added.
|
||||||
|
|
||||||
|
Completion: owned condition sets merge smaller into larger without retaining
|
||||||
|
operand snapshots. For the documented distinct left-heavy cases, source work is
|
||||||
|
3, 15, and 127 insertions at N=4, 16, and 128, respectively, excluding leaf
|
||||||
|
creation (previously 9, 135, and 8,255). Prompt requirements tests pass on Go
|
||||||
|
1.27.3; these counts are not a general complexity guarantee.
|
||||||
|
|
||||||
## Stage 17: Share Requirement Branch Orchestration
|
## Stage 17: Share Requirement Branch Orchestration
|
||||||
|
|
||||||
**Catalog:** 23. **Files:** internal prompt requirement traversal/evaluation.
|
**Catalog:** 23. **Files:** internal prompt requirement traversal/evaluation.
|
||||||
|
|||||||
@@ -319,24 +319,27 @@ func mergeConditionEvaluations(left, right conditionEvaluation) conditionEvaluat
|
|||||||
result := conditionEvaluation{
|
result := conditionEvaluation{
|
||||||
unsupported: left.unsupported || right.unsupported,
|
unsupported: left.unsupported || right.unsupported,
|
||||||
inputNameUnknown: left.inputNameUnknown || right.inputNameUnknown,
|
inputNameUnknown: left.inputNameUnknown || right.inputNameUnknown,
|
||||||
missingVariables: make(map[string]struct{}, len(left.missingVariables)+len(right.missingVariables)),
|
missingVariables: mergeOwnedNames(left.missingVariables, right.missingVariables),
|
||||||
contentInputs: make(map[string]struct{}, len(left.contentInputs)+len(right.contentInputs)),
|
contentInputs: mergeOwnedNames(left.contentInputs, right.contentInputs),
|
||||||
}
|
|
||||||
for name := range left.missingVariables {
|
|
||||||
result.missingVariables[name] = struct{}{}
|
|
||||||
}
|
|
||||||
for name := range right.missingVariables {
|
|
||||||
result.missingVariables[name] = struct{}{}
|
|
||||||
}
|
|
||||||
for name := range left.contentInputs {
|
|
||||||
result.contentInputs[name] = struct{}{}
|
|
||||||
}
|
|
||||||
for name := range right.contentInputs {
|
|
||||||
result.contentInputs[name] = struct{}{}
|
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Condition results own their sets; callers retain operand values and flags,
|
||||||
|
// not independent snapshots of these maps after a merge.
|
||||||
|
func mergeOwnedNames(left, right map[string]struct{}) map[string]struct{} {
|
||||||
|
if len(left) < len(right) {
|
||||||
|
left, right = right, left
|
||||||
|
}
|
||||||
|
if left == nil {
|
||||||
|
return right
|
||||||
|
}
|
||||||
|
for name := range right {
|
||||||
|
left[name] = struct{}{}
|
||||||
|
}
|
||||||
|
return left
|
||||||
|
}
|
||||||
|
|
||||||
func branchReach(parent requirementReachability, known, truth, selected bool) requirementReachability {
|
func branchReach(parent requirementReachability, known, truth, selected bool) requirementReachability {
|
||||||
if parent == requirementInactive {
|
if parent == requirementInactive {
|
||||||
return requirementInactive
|
return requirementInactive
|
||||||
|
|||||||
@@ -406,6 +406,35 @@ func TestAnalyzeRequirementsReportsUnresolvedDecisionAndContentConditions(t *tes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConditionEvaluationMergesOwnedEvidence(t *testing.T) {
|
||||||
|
left := conditionEvaluation{missingVariables: map[string]struct{}{"a": {}, "b": {}}, contentInputs: map[string]struct{}{"document": {}}, unsupported: true}
|
||||||
|
right := conditionEvaluation{missingVariables: map[string]struct{}{"b": {}, "c": {}}, inputNameUnknown: true}
|
||||||
|
merged := mergeConditionEvaluations(left, right)
|
||||||
|
if !merged.unsupported || !merged.inputNameUnknown || len(merged.missingVariables) != 3 || len(merged.contentInputs) != 1 {
|
||||||
|
t.Fatalf("merged evidence = %+v", merged)
|
||||||
|
}
|
||||||
|
transferred := mergeConditionEvaluations(conditionEvaluation{}, conditionEvaluation{missingVariables: map[string]struct{}{"only": {}}})
|
||||||
|
if len(transferred.missingVariables) != 1 || transferred.contentInputs != nil {
|
||||||
|
t.Fatalf("transferred evidence = %+v", transferred)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnalyzeRequirementsRetainsLeftHeavyMissingConditions(t *testing.T) {
|
||||||
|
compiled := compileRequirementTemplate(t, "nested", `{{if eq (eq (eq .a .b) .c) .d}}{{input "yes"}}{{else}}{{input "no"}}{{end}}`)
|
||||||
|
result, err := AnalyzeRequirements(context.Background(), &domain.PromptDefinition{}, RequirementSnapshot{Templates: CompiledTemplates{Messages: []*template.Template{compiled}}}, nil, false)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if result.Complete || len(result.Variables) != 4 || len(result.Inputs) != 2 {
|
||||||
|
t.Fatalf("requirements = %+v", result)
|
||||||
|
}
|
||||||
|
for i, name := range []string{"a", "b", "c", "d"} {
|
||||||
|
if result.Variables[i].Name != name {
|
||||||
|
t.Fatalf("variables = %+v", result.Variables)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestAnalyzeRequirementsRetainsInactiveEntriesAndPromotesActiveUses(t *testing.T) {
|
func TestAnalyzeRequirementsRetainsInactiveEntriesAndPromotesActiveUses(t *testing.T) {
|
||||||
description := "declared for a reason"
|
description := "declared for a reason"
|
||||||
definition := &domain.PromptDefinition{Templates: []domain.PromptMessageTemplate{{
|
definition := &domain.PromptDefinition{Templates: []domain.PromptMessageTemplate{{
|
||||||
|
|||||||
Reference in New Issue
Block a user