package engine import "gitea.maximumdirect.net/eric/ConfigKit/internal/document" // projectTierHistoryApplications composes each strict source's local projection // with the tier operation. The retained source values stay in authored coordinates. func projectTierHistoryApplications(applications []historyApplication, operations []sequenceHistoryContribution) []historyApplication { mapped := false for _, operation := range operations { mapped = mapped || operation.mode == sequenceHistoryMapped } if !mapped { return applications } projections := indexSequenceHistoryContributions(operations) projected := cloneHistoryApplications(applications) for index, original := range applications { application := &projected[index] var originalLookup *documentLookup if path, found := projectSequenceOperationPath(original.path, projections); found { application.path = path } for sequenceIndex, source := range original.sequences { container := appendDestination(original.path, source.path) operation, active := projections[container.String()] if !active || operation.mode != sequenceHistoryMapped { continue } if originalLookup == nil { originalLookup = buildDocumentLookup(original.value) } value, found := documentAtPathWithLookup(original.value, source.path, originalLookup) if !found || value.Kind != document.Sequence { continue } sourceIndex := application.sequencesByPath[source.path.String()] contribution := sequenceHistoryContribution{path: source.path.clone(), mode: sequenceHistoryMapped} for inputIndex := range value.Sequence { tierIndex := source.offset + inputIndex if source.mode == sequenceHistoryMapped { tierIndex = sourceIndex.outputForInput(inputIndex) } outputIndex, present := operation.projection.outputForInput(tierIndex) if !present { continue } contribution.items = append(contribution.items, sequenceItemProjection{inputIndex: inputIndex, outputIndex: outputIndex}) if _, replaced := operation.replacedOutputs[outputIndex]; replaced { // Upsert replacements retain their lower-list position. contribution.replacements = append(contribution.replacements, sequenceItemReplacement{ lowerIndex: outputIndex, higherIndex: inputIndex, outputIndex: outputIndex, }) } } application.sequences[sequenceIndex] = contribution } application.sequencesByPath = indexSequenceHistoryContributions(application.sequences) } return projected } func projectSequenceOperationPath(path Path, projections map[string]sequenceHistoryContributionIndex) (Path, bool) { projected := path.clone() for index, segment := range path.segments { if segment.kind != pathSegmentIndex { continue } prefix := Path{segments: path.segments[:index]} operation, found := projections[prefix.String()] if !found || operation.mode != sequenceHistoryMapped { continue } outputIndex, found := operation.projection.outputForInput(segment.index) if !found { return Path{}, false } projected.segments[index].index = outputIndex } return projected, true } // Project only incoming sources. Lower/displaced sources retain the coordinates // of their own historical contribution, rather than becoming incoming survivors. func projectTierSourceDestinations(sources []SourceInfo, versions []*sourceVersionEvidence, operations []sequenceHistoryContribution) { if len(operations) == 0 { return } projections := indexSequenceHistoryContributions(operations) for index := range sources { if path, found := projectSequenceOperationPath(sources[index].Destination, projections); found { sources[index].Destination = path } } for _, evidence := range versions { if evidence == nil { continue } paths := evidence.sensitivityPaths() projected := make([]Path, len(paths)) for index, path := range paths { projected[index] = path.clone() if destination, found := projectSequenceOperationPath(path, projections); found { projected[index] = destination } } evidence.projectedPaths = projected if path, found := projectSequenceOperationPath(evidence.destination, projections); found { evidence.destination = path } } }