Files
narratio/internal/app/semantic_resume.go

96 lines
2.8 KiB
Go

package app
import (
"context"
"fmt"
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
"gitea.maximumdirect.net/eric/narratio/internal/stage"
)
func currentStageSemanticConfig(selected stage.Stage, env *stage.Env) (*manifest.SemanticConfigFingerprint, error) {
provider, ok := selected.(stage.SemanticConfigFingerprinter)
if !ok {
return nil, nil
}
record, err := provider.SemanticConfigFingerprint(env)
if err != nil {
return nil, err
}
if err := record.Validate(); err != nil {
return nil, fmt.Errorf("invalid current semantic configuration fingerprint: %w", err)
}
return cloneSemanticConfig(&record), nil
}
func validateStageSemanticResume(selected stage.Stage, m *manifest.Manifest, current *manifest.SemanticConfigFingerprint) stage.ResumeValidation {
if current == nil {
return stage.Resumable()
}
var persisted *manifest.SemanticConfigFingerprint
if m != nil && m.Stages != nil && m.Stages[selected.Name()] != nil {
persisted = m.Stages[selected.Name()].SemanticConfig
}
if persisted == nil {
return stage.NonResumable("semantic configuration evidence is missing; rerun the stage to establish current evidence")
}
if err := persisted.Validate(); err != nil {
return stage.NonResumable("persisted semantic configuration evidence is malformed; rerun the stage")
}
if persisted.Version != current.Version {
return stage.NonResumable("semantic configuration contract version changed; rerun the stage")
}
if persisted.Digest != current.Digest {
return stage.NonResumable("result-affecting configuration changed; rerun the stage")
}
return stage.Resumable()
}
func evaluateStageResume(
ctx context.Context,
selected stage.Stage,
env *stage.Env,
m *manifest.Manifest,
current *manifest.SemanticConfigFingerprint,
) (*stage.ResumeValidation, error) {
semantic := validateStageSemanticResume(selected, m, current).Normalized()
if !semantic.Resumable {
return &semantic, nil
}
validator, ok := selected.(stage.ResumeValidator)
if !ok {
if current == nil {
return nil, nil
}
return &semantic, nil
}
validation, err := validator.ValidateResume(ctx, env, m)
if err != nil {
return nil, err
}
validation = validation.Normalized()
return &validation, nil
}
func setSessionStageSemanticConfig(m *manifest.Manifest, name string, value *manifest.SemanticConfigFingerprint) {
if m == nil || m.Stages == nil || m.Stages[name] == nil {
return
}
m.Stages[name].SemanticConfig = cloneSemanticConfig(value)
}
func setRunStageSemanticConfig(m *manifest.RunManifest, name string, value *manifest.SemanticConfigFingerprint) {
if m == nil || m.Stages == nil || m.Stages[name] == nil {
return
}
m.Stages[name].SemanticConfig = cloneSemanticConfig(value)
}
func cloneSemanticConfig(value *manifest.SemanticConfigFingerprint) *manifest.SemanticConfigFingerprint {
if value == nil {
return nil
}
copy := *value
return &copy
}