From fa6e876ab5496a0867a19809c349bd30c893a85d Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sun, 25 Oct 2026 13:43:26 +0000 Subject: [PATCH] Extract inheritance accounting and finalization --- docs/roadmap/implementation.md | 10 ++++- internal/engine/inheritance_finalize.go | 55 +++++++++++++++++++++++++ internal/engine/inheritance_schedule.go | 35 ++-------------- 3 files changed, 67 insertions(+), 33 deletions(-) create mode 100644 internal/engine/inheritance_finalize.go diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index aa11654..53ed5a6 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # Consolidation Implementation Plan -Status: in progress. Stages 1 through 15 are complete; follow Stage 16 through Stage 20 in order. +Status: in progress. Stages 1 through 16 are complete; follow Stage 17 through Stage 20 in order. The target executor is a Luna coding agent working through one end-to-end sprint. ## Authority, Baseline, And Execution @@ -627,7 +627,7 @@ sequence-origin handling returns replacement records to the template result. Parentless templates use the same result shape. Engine and facade inheritance tests passed. -## Stage 16 — Finish The Inheritance Executor And Accounting +## Stage 16 — Finish The Inheritance Executor And Accounting (Complete) **Owner:** engine `inheritance_schedule.go` and focused finalization helpers. @@ -649,6 +649,12 @@ tests passed. **Finish:** one readable executor coordinates explicit value/policy/evidence handoffs, with no parallel inheritance implementation. Run I. +Progress notes (2026-10-25): extracted per-template retained-history charging and +scope rebuild/origin/policy projection into `inheritance_finalize.go`. The shared +counter, budget checks, final expansion check, and one policy index remain intact. +Both mapping and identified-sequence adapters still use the shared executor. +Validation group I passed. + ## Stage 17 — Extract Substantial Projection Handlers **Owners:** engine `projection.go`, optionally new `projection_collection.go`. diff --git a/internal/engine/inheritance_finalize.go b/internal/engine/inheritance_finalize.go new file mode 100644 index 0000000..8ef6e68 --- /dev/null +++ b/internal/engine/inheritance_finalize.go @@ -0,0 +1,55 @@ +package engine + +import "gitea.maximumdirect.net/eric/ConfigKit/internal/document" + +func chargeInheritanceTemplateHistory(counter *retainedNodeCounter, result inheritanceTemplateResult, template inheritanceExecutionTemplate) *Diagnostic { + for _, operation := range result.operations { + if !counter.add(operation.parent) || !counter.add(operation.effective) { + diagnostic := inheritanceHistoryBudgetDiagnostic(template.path, template.entry.Value.Location) + return &diagnostic + } + } + for _, replacement := range result.replacements { + if !counter.add(replacement.before) || !counter.add(replacement.after) { + diagnostic := inheritanceHistoryBudgetDiagnostic(template.path, template.entry.Value.Location) + return &diagnostic + } + } + return nil +} + +func finalizeInheritanceScope( + adapter inheritanceScopeAdapter, + result *inheritanceScope, + templates []inheritanceExecutionTemplate, + resolved []*document.Node, + resolvedOrigins []map[string]Origin, + resolvedPolicies []collectionPolicyScope, + inputOrigins map[string]Origin, + limits projectionLimits, +) []Diagnostic { + root := adapter.rebuild(resolved) + result.collectionPolicies = collectionPolicyScope{} + result.origins = directInheritanceOrigins(&document.Node{Kind: root.Kind, Location: root.Location}, adapter.scopePath(), inputOrigins) + policyIndex := newInheritancePolicyIndex(adapter.collectionPolicies()) + for _, slot := range adapter.slots() { + if slot.hasTemplate { + index := slot.template + projectInheritancePolicyRoots(&result.collectionPolicies, resolvedPolicies[index], templates[index].path) + for pointer, origin := range resolvedOrigins[index] { + result.origins[pointer] = origin + } + continue + } + localPolicies := policyIndex.localize(slot.path) + projectInheritancePolicyRoots(&result.collectionPolicies, localPolicies, slot.path) + for pointer, origin := range directInheritanceOrigins(slot.value, slot.path, inputOrigins) { + result.origins[pointer] = origin + } + } + result.root = root + if !inheritanceLowerBoundWithin(result.root, limits.nodes) { + return []Diagnostic{inheritanceBudgetDiagnostic(adapter.scopePath(), adapter.scope().Location)} + } + return nil +} diff --git a/internal/engine/inheritance_schedule.go b/internal/engine/inheritance_schedule.go index 957f200..eab7766 100644 --- a/internal/engine/inheritance_schedule.go +++ b/internal/engine/inheritance_schedule.go @@ -227,40 +227,13 @@ func applyInheritanceScopeTemplates(adapter inheritanceScopeAdapter, order []int count, _ := inheritanceLowerBoundCount(resolved[index], limits.nodes) retained += adapter.slotOverhead() + count - for _, operation := range templateResult.operations { - if !counter.add(operation.parent) || !counter.add(operation.effective) { - return nil, []Diagnostic{inheritanceHistoryBudgetDiagnostic(node.path, node.entry.Value.Location)} - } - } - for _, replacement := range templateResult.replacements { - if !counter.add(replacement.before) || !counter.add(replacement.after) { - return nil, []Diagnostic{inheritanceHistoryBudgetDiagnostic(node.path, node.entry.Value.Location)} - } + if diagnostic := chargeInheritanceTemplateHistory(counter, templateResult, node); diagnostic != nil { + return nil, []Diagnostic{*diagnostic} } } - root := adapter.rebuild(resolved) - result.collectionPolicies = collectionPolicyScope{} - result.origins = directInheritanceOrigins(&document.Node{Kind: root.Kind, Location: root.Location}, adapter.scopePath(), inputOrigins) - policyIndex := newInheritancePolicyIndex(adapter.collectionPolicies()) - for _, slot := range adapter.slots() { - if slot.hasTemplate { - index := slot.template - projectInheritancePolicyRoots(&result.collectionPolicies, resolvedPolicies[index], templates[index].path) - for pointer, origin := range resolvedOrigins[index] { - result.origins[pointer] = origin - } - continue - } - localPolicies := policyIndex.localize(slot.path) - projectInheritancePolicyRoots(&result.collectionPolicies, localPolicies, slot.path) - for pointer, origin := range directInheritanceOrigins(slot.value, slot.path, inputOrigins) { - result.origins[pointer] = origin - } - } - result.root = root - if !inheritanceLowerBoundWithin(result.root, limits.nodes) { - return nil, []Diagnostic{inheritanceBudgetDiagnostic(adapter.scopePath(), adapter.scope().Location)} + if diagnostics := finalizeInheritanceScope(adapter, result, templates, resolved, resolvedOrigins, resolvedPolicies, inputOrigins, limits); len(diagnostics) != 0 { + return nil, diagnostics } return result, nil }