Share layered tier application

This commit is contained in:
2026-10-25 22:37:46 +00:00
parent a8ae2e9d5e
commit 883244936c
3 changed files with 60 additions and 32 deletions

View File

@@ -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`

View File

@@ -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**.

View File

@@ -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{}}