From 883244936c0668628072f646c187d9622cad9722 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Sun, 25 Oct 2026 22:37:46 +0000 Subject: [PATCH] Share layered tier application --- docs/internal/overview.md | 5 ++- docs/roadmap/implementation.md | 7 +++ internal/engine/load_request.go | 80 ++++++++++++++++++++------------- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 3dc86b3..a07eb77 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -101,7 +101,10 @@ source, filesystem, destination, and import settings. policy, load-wide accounting, and tier-scoped repetition/namespace state. Each input is acquired under that policy; grouped requests retain acquired underlay scopes until their tier is composed in -[`load_request.go`](../../internal/engine/load_request.go). Live +[`load_request.go`](../../internal/engine/load_request.go). Completed tiers then +share one assembly handoff that applies collection declarations and projects +only that tier's source/version evidence; the caller keeps main-version +protection and its projection explicit. Live filesystem access handles are confined to acquisition and closed there. Resolved filesystem facts used to authorize access are separate from passively retained resource contexts. Non-import validation retains those facts on `assembledInput` diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index e569bd8..67aa8d8 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -782,6 +782,13 @@ metadata/history/diff, and warnings remain stable. Update the implementation-flo description only after the handoffs actually land, without restating YAML policy. Focused check: `go test ./internal/engine -run 'Grouped|Layered|Underlay|SourceVersion|Sequence|Diff'`. +Status: **complete** (completes F02). Prior completed F02 commits: +`4bf940c`, `d8bf6ab`, `f185821`, and `a8ae2e9`. Validation passed: +`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -run 'Grouped|Layered|Underlay|SourceVersion|Sequence|Diff' -count=1`, +`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./internal/engine -count=1`, +`env GOTOOLCHAIN=local GOPROXY=off GOTELEMETRY=off go test ./... -count=1`, +and `git diff --check`. + ## Stage 25 — Separate Collection Preparation, Application, And Finalization Finding: preparation/ownership part of **E03**. diff --git a/internal/engine/load_request.go b/internal/engine/load_request.go index 9adac05..a79e9d2 100644 --- a/internal/engine/load_request.go +++ b/internal/engine/load_request.go @@ -113,21 +113,12 @@ func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, p return input, diagnostics } if composition != nil { - if assembly == nil { - assembly = newAssemblyAccumulator(composition) - } else { - var declarations []sequenceDeclarationSpec - for _, scope := range composition.acquisition { - declarations = append(declarations, acquiredSequenceDeclarations(scope)...) - } - operations, diagnostics := assembly.applyOverlayWithCollectionProjection( - composition.root, composition.origins, composition.collectionPolicies, composition.applications, LayerUnderlay, - policy.sequencePolicy, declarations, - ) - if len(diagnostics) != 0 { - return input, diagnostics - } - projectTierSourceDestinations(input.sources[sourceStart:], input.versionState.evidenceSince(evidenceStart), operations) + _, diagnostics = applyCompletedTier( + &assembly, composition, composition.collectionPolicies, LayerUnderlay, policy.sequencePolicy, + input.sources[sourceStart:], input.versionState.evidenceSince(evidenceStart), + ) + if len(diagnostics) != 0 { + return input, diagnostics } } } @@ -160,23 +151,14 @@ func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, p } if mainComposition != nil { input.versionState.locateMainVersion(mainComposition.root) - if assembly == nil { - assembly = newAssemblyAccumulator(mainComposition) - } else { - var declarations []sequenceDeclarationSpec - for _, scope := range mainComposition.acquisition { - declarations = append(declarations, acquiredSequenceDeclarations(scope)...) - } - operations, diagnostics := assembly.applyOverlayWithCollectionProjection( - mainComposition.root, mainComposition.origins, mainComposition.collectionPolicies, mainComposition.applications, LayerBase, - policy.sequencePolicy, declarations, - ) - if len(diagnostics) != 0 { - return input, append(versionDiagnostics, diagnostics...) - } - projectTierSourceDestinations(input.sources[:mainSourceCount], mainEvidence, operations) - input.versionState.projectMainVersion(operations) + operations, diagnostics := applyCompletedTier( + &assembly, mainComposition, mainComposition.collectionPolicies, LayerBase, policy.sequencePolicy, + input.sources[:mainSourceCount], mainEvidence, + ) + if len(diagnostics) != 0 { + return input, append(versionDiagnostics, diagnostics...) } + input.versionState.projectMainVersion(operations) } if input.versionState != nil { request.effectiveVersion = input.versionState.effectiveRule @@ -230,6 +212,42 @@ func assembleLayeredInput[T any](request loadRequest[T], input assembledInput, p return input, versionDiagnostics } +// applyCompletedTier joins one already-composed precedence tier to the load's +// assembly and projects only that tier's source/version evidence through the +// resulting sequence operations. Callers select the tier-local evidence ranges +// so lower-tier and main-tier coordinates remain distinct. +func applyCompletedTier( + assembly **assemblyAccumulator, + composition *composedDocument, + incomingPolicies collectionPolicyScope, + layer Layer, + sequencePolicy sequencePolicy, + incomingSources []SourceInfo, + incomingVersions []*sourceVersionEvidence, +) ([]sequenceHistoryContribution, []Diagnostic) { + if composition == nil { + return nil, nil + } + if *assembly == nil { + *assembly = newAssemblyAccumulator(composition) + return nil, nil + } + + var declarations []sequenceDeclarationSpec + for _, scope := range composition.acquisition { + declarations = append(declarations, acquiredSequenceDeclarations(scope)...) + } + operations, diagnostics := (*assembly).applyOverlayWithCollectionProjection( + composition.root, composition.origins, incomingPolicies, composition.applications, layer, + sequencePolicy, declarations, + ) + if len(diagnostics) != 0 { + return nil, diagnostics + } + projectTierSourceDestinations(incomingSources, incomingVersions, operations) + return operations, nil +} + func acquireUnderlayGroupScopes(group loadGroup, index int, rule *VersionRule, state *acquisitionState, policy acquisitionPolicy) (*acquiredUnderlayGroup, []Diagnostic) { initialBytes, initialNodes := state.accounting.bytes, state.accounting.nodes tier := &tierAcquisitionState{visited: make(map[resourceIdentity]importRoute), hostToken: &namespaceToken{}}