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 © }