Run ordered processing with independent settings
This commit is contained in:
@@ -7,11 +7,14 @@ import (
|
||||
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/config"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/diagnostics"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/glossary"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/modulecatalog"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/schema"
|
||||
)
|
||||
|
||||
// Input contains already acquired application and transcript inputs.
|
||||
type Input struct {
|
||||
InspectProfile func(context.Context, string) error
|
||||
Config *config.Config
|
||||
Transcript *schema.SourceTranscript
|
||||
Output diagnostics.OutputSelection
|
||||
@@ -45,6 +48,9 @@ func Prepare(ctx context.Context, input Input) (*Prepared, error) {
|
||||
if input.Transcript == nil {
|
||||
return nil, fmt.Errorf("transcript is required")
|
||||
}
|
||||
if err := CheckReadiness(ctx, input.Config, input.InspectProfile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
session, err := diagnostics.SelectOutput(input.Output)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -74,3 +80,38 @@ func Prepare(ctx context.Context, input Input) (*Prepared, error) {
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// CheckReadiness checks all resolved processing selections before output preparation.
|
||||
func CheckReadiness(ctx context.Context, cfg *config.Config, inspectProfile func(context.Context, string) error) error {
|
||||
if cfg == nil {
|
||||
return fmt.Errorf("application configuration is required")
|
||||
}
|
||||
label := func(index int, item config.Stage) string {
|
||||
if item.ID != nil {
|
||||
return fmt.Sprintf("stage %d (%s, id %q)", index+1, item.Module, *item.ID)
|
||||
}
|
||||
return fmt.Sprintf("stage %d (%s)", index+1, item.Module)
|
||||
}
|
||||
for index, item := range cfg.Pipeline.Stages {
|
||||
if item.Module == modulecatalog.KeyGlossary && len(glossary.Select(cfg.GlossaryCollections, item.Glossaries)) == 0 {
|
||||
return fmt.Errorf("%s has no glossary entries in selected collections %q", label(index, item), item.Glossaries)
|
||||
}
|
||||
}
|
||||
for index, item := range cfg.Pipeline.Stages {
|
||||
for _, selection := range []struct {
|
||||
role string
|
||||
profile *string
|
||||
}{{"proposal", item.LLM.ProposalProfile}, {"validation", item.LLM.ValidationProfile}} {
|
||||
if selection.profile == nil || *selection.profile == "" {
|
||||
return fmt.Errorf("%s requires a %s profile", label(index, item), selection.role)
|
||||
}
|
||||
if inspectProfile == nil {
|
||||
return fmt.Errorf("profile inspection is required")
|
||||
}
|
||||
if err := inspectProfile(ctx, *selection.profile); err != nil {
|
||||
return fmt.Errorf("%s %s profile %q: %w", label(index, item), selection.role, *selection.profile, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
39
internal/framework/preflight/readiness_test.go
Normal file
39
internal/framework/preflight/readiness_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package preflight
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/config"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/diagnostics"
|
||||
"gitea.maximumdirect.net/eric/audita/v3/internal/core/schema"
|
||||
)
|
||||
|
||||
func TestLaterEmptyGlossaryFailsBeforeOutputPreparation(t *testing.T) {
|
||||
profile, id := "selected", "spells"
|
||||
cfg := &config.Config{Pipeline: config.Pipeline{Stages: []config.Stage{
|
||||
{Module: "grammar", LLM: config.LLM{ProposalProfile: &profile, ValidationProfile: &profile}},
|
||||
{Module: "glossary", ID: &id, Glossaries: []string{"empty"}, LLM: config.LLM{ProposalProfile: &profile, ValidationProfile: &profile}},
|
||||
}}}
|
||||
output := filepath.Join(t.TempDir(), "transcript.json")
|
||||
calls := 0
|
||||
_, err := Prepare(context.Background(), Input{Config: cfg, Transcript: &schema.SourceTranscript{}, Output: diagnostics.OutputSelection{TranscriptPath: output}, InspectProfile: func(context.Context, string) error { calls++; return nil }})
|
||||
if err == nil || !strings.Contains(err.Error(), "stage 2") || !strings.Contains(err.Error(), "spells") || !strings.Contains(err.Error(), "empty") {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if calls != 0 {
|
||||
t.Fatal("inspected profiles before checking all glossary selections")
|
||||
}
|
||||
if _, err := os.Stat(output); !os.IsNotExist(err) {
|
||||
t.Fatalf("output exists: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyPipelineNeedsNoProfile(t *testing.T) {
|
||||
if err := CheckReadiness(context.Background(), &config.Config{}, nil); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user