Unify previous source resolution

This commit is contained in:
2026-08-10 21:20:59 +00:00
parent d9fa1d9328
commit b39b68add7
20 changed files with 406 additions and 76 deletions

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"path"
"path/filepath"
"sort"
"strings"
@@ -40,9 +39,13 @@ type Record struct {
Size int64
Generation string
S3Bucket string
VerifiedContent []byte
}
func BuildPlan(
// Resolve evaluates previous-session requirements against the one selected
// remote current state. Optional absence is represented in SkippedMissing;
// required absence returns an error.
func Resolve(
ctx context.Context,
cfg *config.Config,
paths artifacts.SessionPaths,
@@ -137,45 +140,44 @@ func BuildPlan(
manifestRecord.SHA256 = committedManifest.SHA256
manifestRecord.Size = committedManifest.Size
manifestRecord.Generation = committedManifest.Generation
manifestRecord.VerifiedContent = append([]byte(nil), current.ManifestData...)
}
result.Records = append(result.Records, manifestRecord)
for _, requirement := range orderedRequirements {
candidates := artifactRelativePathCandidates(requirement.Name, previousManifest, cfg)
if len(candidates) == 0 {
if requirement.Required {
return nil, fmt.Errorf(
"required previous-session artifact %q is unavailable in previous-session manifest/published-state",
requirement.Name,
)
}
result.SkippedMissing = append(result.SkippedMissing, requirement.Name)
continue
}
selectedRel := ""
selectedKey := ""
var selectedArtifact *artifacts.RemoteArtifact
for _, candidate := range candidates {
if current.Commit != nil {
artifact, ok := committedPublishedArtifact(current.Commit, previousSessionPrefix, candidate)
if !ok {
continue
if current.Commit != nil {
sourceID := previousArtifactSourceID(requirement.Name)
artifact, ok := committedPublishedArtifactBySource(current.Commit, sourceID)
if ok {
selectedRel, ok = sourceRelativePath(sourceID, requirement.Name, previousManifest, cfg)
if ok {
selectedKey = artifact.DestinationKey
selectedArtifact = &artifact
}
selectedRel = candidate
selectedKey = artifact.DestinationKey
selectedArtifact = &artifact
break
}
remoteKey := artifacts.S3PublishedOutputKey(previousSessionPrefix, candidate)
exists, err := store.Exists(ctx, remoteKey)
if err != nil {
return nil, fmt.Errorf("check previous-session artifact object %q: %w", remoteKey, err)
} else {
// Legacy current state predates immutable source-to-destination
// mappings. Keep its compatibility candidates isolated here.
matchedCandidates := make([]string, 0, 1)
for _, candidate := range legacyArtifactRelativePathCandidates(requirement.Name, previousManifest, cfg) {
remoteKey := artifacts.S3PublishedOutputKey(previousSessionPrefix, candidate)
exists, err := store.Exists(ctx, remoteKey)
if err != nil {
return nil, fmt.Errorf("check previous-session artifact object %q: %w", remoteKey, err)
}
if exists {
matchedCandidates = append(matchedCandidates, candidate)
if len(matchedCandidates) == 1 {
selectedRel = candidate
selectedKey = remoteKey
}
}
}
if exists {
selectedRel = candidate
selectedKey = remoteKey
break
if len(matchedCandidates) > 1 {
return nil, fmt.Errorf("legacy previous-session artifact %q matches multiple published candidates: %s", requirement.Name, strings.Join(matchedCandidates, ", "))
}
}
if selectedRel == "" {
@@ -224,13 +226,27 @@ func BuildPlan(
return result, nil
}
func committedPublishedArtifact(commit *artifacts.RemoteCommitManifest, sessionPrefix, relativePath string) (artifacts.RemoteArtifact, bool) {
// BuildPlan is retained for callers that need the historical name.
func BuildPlan(
ctx context.Context,
cfg *config.Config,
paths artifacts.SessionPaths,
requirements []artifacts.PreviousArtifactRequirement,
store storage.ObjectStore,
) (*Plan, error) {
return Resolve(ctx, cfg, paths, requirements, store)
}
func committedPublishedArtifactBySource(commit *artifacts.RemoteCommitManifest, source string) (artifacts.RemoteArtifact, bool) {
if commit == nil {
return artifacts.RemoteArtifact{}, false
}
want := artifacts.S3RunRelativeDestinationKey(artifacts.S3RunPrefix(sessionPrefix, commit.RunID), relativePath)
want := strings.TrimSpace(source)
if want == "" {
return artifacts.RemoteArtifact{}, false
}
for _, artifact := range commit.Artifacts {
if artifact.Type == artifacts.RemoteArtifactTypePublishedOutput && artifact.DestinationKey == want {
if artifact.Type == artifacts.RemoteArtifactTypePublishedOutput && artifact.Source == want {
return artifact, true
}
}
@@ -260,7 +276,30 @@ func optionalPreviousArtifactNames(requirements []artifacts.PreviousArtifactRequ
return names
}
func artifactRelativePathCandidates(
func previousArtifactSourceID(artifactName string) string {
sourceID := artifactpolicy.ConfiguredSourceID(artifactName)
if sourceDescriptor, err := artifactpolicy.PreviousSessionSourceDescriptorForConfiguredKey(artifactName); err == nil {
sourceID = sourceDescriptor.ConfiguredSourceID
}
return sourceID
}
func sourceRelativePath(sourceID, artifactName string, previousManifest *manifest.Manifest, cfg *config.Config) (string, bool) {
if rel, ok := manifestArtifactRelativePathBySourceID(previousManifest, sourceID); ok {
return rel, true
}
if cfg != nil && cfg.Pipeline != nil && cfg.Pipeline.Scriptorium != nil {
if artifactCfg, ok := cfg.Pipeline.Scriptorium.Artifacts[artifactName]; ok {
normalized, err := pathsafe.NormalizeRelativeDestination(artifactCfg.OutputPath)
if err == nil {
return normalized, true
}
}
}
return "", false
}
func legacyArtifactRelativePathCandidates(
artifactName string,
previousManifest *manifest.Manifest,
cfg *config.Config,
@@ -274,16 +313,12 @@ func artifactRelativePathCandidates(
candidates = append(candidates, normalized)
}
sourceDescriptor, err := artifactpolicy.PreviousSessionSourceDescriptorForConfiguredKey(artifactName)
sourceID := artifactpolicy.ConfiguredSourceID(artifactName)
if err == nil {
sourceID = sourceDescriptor.ConfiguredSourceID
}
sourceID := previousArtifactSourceID(artifactName)
if rel, ok := manifestArtifactRelativePathBySourceID(previousManifest, sourceID); ok {
appendCandidate(rel)
base := path.Base(rel)
base := filepath.Base(rel)
for _, published := range manifestPublishedPaths(previousManifest) {
if path.Base(published) == base {
if filepath.Base(published) == base {
appendCandidate(published)
}
}