Simplify stage and Audita contracts

This commit is contained in:
2026-08-10 22:43:22 +00:00
parent 131ffd9887
commit b89224bbde
21 changed files with 47 additions and 271 deletions

View File

@@ -15,7 +15,12 @@ runner composition is documented in
- required transcript/glossary/output/work-dir paths; - required transcript/glossary/output/work-dir paths;
- optional report path (required when report mode is enabled); - optional report path (required when report mode is enabled);
- generated config and stdout/stderr log paths; - generated config and stdout/stderr log paths;
- optional module/model/base-url/config/output-schema/concurrency settings. - optional per-invocation module override.
The constructed runner owns static Audita settings: binary, timeout,
credentials, default modules, model and endpoint settings, validation and output
settings, report mode, and concurrency. The `polish` stage supplies only
invocation-specific paths and may override modules for that invocation.
## Result Contract ## Result Contract
`PolishResult` returns: `PolishResult` returns:

View File

@@ -17,7 +17,8 @@ Run Audita polishing on base transcript and produce polished transcript.
## Key Behavior ## Key Behavior
- resolves base transcript from merge outputs/canonical fallback. - resolves base transcript from merge outputs/canonical fallback.
- invokes Audita with configured model/module/runtime options. - invokes an Audita runner configured with static model/runtime options; the
invocation supplies paths and modules.
- validates processed transcript structure (`segments` array required). - validates processed transcript structure (`segments` array required).
- validates optional report JSON. - validates optional report JSON.
- materializes canonical outputs; records logs/generated config and adapter metadata. - materializes canonical outputs; records logs/generated config and adapter metadata.

View File

@@ -1014,6 +1014,8 @@ stabilized and place static Audita policy in its constructor.
tests, search for removed symbols/TODOs/stale request fields, and confirm public tests, search for removed symbols/TODOs/stale request fields, and confirm public
package documentation matches the remaining contract. package documentation matches the remaining contract.
**Status:** Completed.
## Stage 31 — Enforce CI validation and streamline the assembled test suite ## Stage 31 — Enforce CI validation and streamline the assembled test suite
**Read first:** `audit-findings.md` lines 38223836 (TST-012) and 38693885 **Read first:** `audit-findings.md` lines 38223836 (TST-012) and 38693885

View File

@@ -6,8 +6,6 @@ import (
"time" "time"
) )
// TODO: implement a real Audita subprocess/service adapter.
// Runner is the adapter boundary for audita polish invocations. // Runner is the adapter boundary for audita polish invocations.
type Runner interface { type Runner interface {
Run(ctx context.Context, req PolishRequest) (PolishResult, error) Run(ctx context.Context, req PolishRequest) (PolishResult, error)
@@ -15,25 +13,15 @@ type Runner interface {
// PolishRequest describes an audita invocation. // PolishRequest describes an audita invocation.
type PolishRequest struct { type PolishRequest struct {
GeneratedConfigPath string GeneratedConfigPath string
MergedTranscriptPath string MergedTranscriptPath string
OutputProcessedPath string OutputProcessedPath string
GlossaryPath string GlossaryPath string
ReportPath string ReportPath string
WorkDir string WorkDir string
Modules []string Modules []string
BaseURL string StdoutLogPath string
Model string StderrLogPath string
TranscriptDescription string
ConfigPath string
OutputSchema string
WorkDirRetention string
TotalLLMConcurrency *int
ProposalLLMConcurrency *int
ValidationModel string
ValidationLLMConcurrency *int
StdoutLogPath string
StderrLogPath string
} }
// PolishResult describes a polish output. // PolishResult describes a polish output.

View File

@@ -22,8 +22,7 @@ type publishSuccessStage struct {
targets *cleanupSeed targets *cleanupSeed
} }
func (publishSuccessStage) Name() string { return "publish" } func (publishSuccessStage) Name() string { return "publish" }
func (publishSuccessStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s publishSuccessStage) Run(_ context.Context, _ *stage.Env, m *manifest.Manifest) (*stage.StageResult, error) { func (s publishSuccessStage) Run(_ context.Context, _ *stage.Env, m *manifest.Manifest) (*stage.StageResult, error) {
if s.targets != nil { if s.targets != nil {
s.targets.runWorkDir = m.LocalWorkDir s.targets.runWorkDir = m.LocalWorkDir
@@ -56,8 +55,7 @@ func (s publishSuccessStage) Run(_ context.Context, _ *stage.Env, m *manifest.Ma
type notifyFailStage struct{} type notifyFailStage struct{}
func (notifyFailStage) Name() string { return "notify" } func (notifyFailStage) Name() string { return "notify" }
func (notifyFailStage) Declares() stage.IODecl { return stage.IODecl{} }
func (notifyFailStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (notifyFailStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
return nil, errors.New("notify failed") return nil, errors.New("notify failed")
} }

View File

@@ -29,8 +29,7 @@ type failingStage struct {
err error err error
} }
func (s failingStage) Name() string { return s.name } func (s failingStage) Name() string { return s.name }
func (s failingStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s failingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s failingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
return nil, s.err return nil, s.err
} }
@@ -47,8 +46,7 @@ type resultStage struct {
order *[]string order *[]string
} }
func (s resultStage) Name() string { return s.name } func (s resultStage) Name() string { return s.name }
func (s resultStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s resultStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s resultStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
if s.runs != nil { if s.runs != nil {
*s.runs = *s.runs + 1 *s.runs = *s.runs + 1
@@ -59,8 +57,7 @@ func (s resultStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest)
return s.result, nil return s.result, nil
} }
func (s countingStage) Name() string { return s.name } func (s countingStage) Name() string { return s.name }
func (s countingStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s countingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s countingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
*s.runs = *s.runs + 1 *s.runs = *s.runs + 1
return &stage.StageResult{Metadata: map[string]any{"counting": true}}, nil return &stage.StageResult{Metadata: map[string]any{"counting": true}}, nil
@@ -86,8 +83,7 @@ type resumeCheckingStage struct {
runs *int runs *int
} }
func (s resumeCheckingStage) Name() string { return s.name } func (s resumeCheckingStage) Name() string { return s.name }
func (s resumeCheckingStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s resumeCheckingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s resumeCheckingStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
*s.runs++ *s.runs++
return &stage.StageResult{}, nil return &stage.StageResult{}, nil
@@ -96,15 +92,13 @@ func (s resumeCheckingStage) ValidateResume(_ context.Context, _ *stage.Env, _ *
return s.validation, s.validateErr return s.validation, s.validateErr
} }
func (s captureNotariusStage) Name() string { return "extract" } func (s captureNotariusStage) Name() string { return "extract" }
func (s captureNotariusStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s captureNotariusStage) Run(_ context.Context, env *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s captureNotariusStage) Run(_ context.Context, env *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
*s.captured = env.Notarius != nil *s.captured = env.Notarius != nil
return &stage.StageResult{}, nil return &stage.StageResult{}, nil
} }
func (s captureSelectedArtifactsStage) Name() string { return s.name } func (s captureSelectedArtifactsStage) Name() string { return s.name }
func (s captureSelectedArtifactsStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s captureSelectedArtifactsStage) Run(_ context.Context, env *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s captureSelectedArtifactsStage) Run(_ context.Context, env *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
if s.captured != nil { if s.captured != nil {
*s.captured = append((*s.captured)[:0], env.SelectedArtifactKeys...) *s.captured = append((*s.captured)[:0], env.SelectedArtifactKeys...)
@@ -112,8 +106,7 @@ func (s captureSelectedArtifactsStage) Run(_ context.Context, env *stage.Env, _
return &stage.StageResult{Metadata: map[string]any{"captured": true}}, nil return &stage.StageResult{Metadata: map[string]any{"captured": true}}, nil
} }
func (captureConfigStage) Name() string { return "prepare" } func (captureConfigStage) Name() string { return "prepare" }
func (captureConfigStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s captureConfigStage) Run(_ context.Context, env *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s captureConfigStage) Run(_ context.Context, env *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
*s.captured = env.Config *s.captured = env.Config
return &stage.StageResult{}, nil return &stage.StageResult{}, nil
@@ -123,8 +116,7 @@ type analyzeOutputStage struct {
output artifacts.Ref output artifacts.Ref
} }
func (s analyzeOutputStage) Name() string { return "analyze" } func (s analyzeOutputStage) Name() string { return "analyze" }
func (s analyzeOutputStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s analyzeOutputStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) { func (s analyzeOutputStage) Run(_ context.Context, _ *stage.Env, _ *manifest.Manifest) (*stage.StageResult, error) {
return &stage.StageResult{ return &stage.StageResult{
Outputs: []artifacts.Ref{s.output}, Outputs: []artifacts.Ref{s.output},
@@ -135,8 +127,7 @@ type selectedAnalyzeArtifactStage struct {
expected []string expected []string
} }
func (s selectedAnalyzeArtifactStage) Name() string { return "analyze" } func (s selectedAnalyzeArtifactStage) Name() string { return "analyze" }
func (s selectedAnalyzeArtifactStage) Declares() stage.IODecl { return stage.IODecl{} }
func (s selectedAnalyzeArtifactStage) Run(_ context.Context, env *stage.Env, m *manifest.Manifest) (*stage.StageResult, error) { func (s selectedAnalyzeArtifactStage) Run(_ context.Context, env *stage.Env, m *manifest.Manifest) (*stage.StageResult, error) {
if len(env.SelectedArtifactKeys) != len(s.expected) { if len(env.SelectedArtifactKeys) != len(s.expected) {
return nil, fmt.Errorf("selected artifacts len = %d, want %d", len(env.SelectedArtifactKeys), len(s.expected)) return nil, fmt.Errorf("selected artifacts len = %d, want %d", len(env.SelectedArtifactKeys), len(s.expected))

View File

@@ -6,14 +6,8 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"gitea.maximumdirect.net/eric/narratio/internal/config"
) )
func resolveSessionConfigPath(flagValue string) (string, error) {
return resolveSessionConfigPathWithCandidates(flagValue, config.DefaultSessionConfigSearchPaths)
}
func resolveSessionConfigPathWithCandidates(flagValue string, candidates []string) (string, error) { func resolveSessionConfigPathWithCandidates(flagValue string, candidates []string) (string, error) {
if explicit := strings.TrimSpace(flagValue); explicit != "" { if explicit := strings.TrimSpace(flagValue); explicit != "" {
return explicit, nil return explicit, nil

View File

@@ -127,7 +127,7 @@ func ParsePreviousSessionSource(source string) (string, bool) {
return matches[1], true return matches[1], true
} }
// ClassifySource classifies a source id as built-in, configured, or previous-session configured. // ClassifySource classifies a source id as built-in, configured, extraction, or previous-session configured.
func ClassifySource(source string) (Source, error) { func ClassifySource(source string) (Source, error) {
trimmed := strings.TrimSpace(source) trimmed := strings.TrimSpace(source)
if trimmed == "" { if trimmed == "" {

View File

@@ -21,17 +21,6 @@ type analyzeStage struct{}
func (analyzeStage) Name() string { return "analyze" } func (analyzeStage) Name() string { return "analyze" }
func (analyzeStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "transcript_polished", Category: "transcripts", RelativePath: "transcripts/polished.json"},
{Kind: "transcript_final", Category: "transcripts", RelativePath: "transcripts/final.json"},
{Kind: "transcript_final_trimmed", Category: "transcripts", RelativePath: "transcripts/final.trimmed.json"},
},
Outputs: nil,
}
}
type analyzeArtifactExecutionPlan struct { type analyzeArtifactExecutionPlan struct {
Name string Name string
Cfg config.ScriptoriumArtifactConfig Cfg config.ScriptoriumArtifactConfig

View File

@@ -33,21 +33,6 @@ type extractStage struct{}
func (extractStage) Name() string { return "extract" } func (extractStage) Name() string { return "extract" }
func (extractStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{{
Kind: artifactmodel.TranscriptOutputKindFinalTrimmed,
SourceID: artifactmodel.SourceTranscriptFinalTrimmed,
Category: "transcripts",
RelativePath: artifactmodel.TranscriptPathFinalTrimmed,
}},
Outputs: []artifacts.Ref{
{Kind: extractLaneOutputKind, Category: "artifacts", RelativePath: "artifacts/notarius/<run-id>/lanes/*.json"},
{Kind: extractIndexOutputKind, Category: "artifacts", RelativePath: "artifacts/notarius/<run-id>/index.json"},
},
}
}
func (extractStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (extractStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil || env.Config.Pipeline == nil || env.Config.Session == nil { if env == nil || env.Config == nil || env.Config.Pipeline == nil || env.Config.Session == nil {
return nil, fmt.Errorf("extract: resolved stage environment config is required") return nil, fmt.Errorf("extract: resolved stage environment config is required")

View File

@@ -19,20 +19,6 @@ type mergeStage struct{}
func (mergeStage) Name() string { return "merge" } func (mergeStage) Name() string { return "merge" }
func (mergeStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "transcript_raw", Category: "transcripts", RelativePath: "transcripts/raw/*.json"},
{Kind: "speakers", Category: "inputs", RelativePath: "inputs/speakers.yml"},
{Kind: "autocorrect", Category: "inputs", RelativePath: "inputs/autocorrect.yml"},
},
Outputs: []artifacts.Ref{
{Kind: "transcript_base", Category: "transcripts", RelativePath: "transcripts/base.json"},
{Kind: "seriatim_report", Category: "artifacts", RelativePath: "artifacts/seriatim.report.json"},
},
}
}
func (mergeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (mergeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil { if env == nil || env.Config == nil {
return nil, fmt.Errorf("merge: stage environment config is required") return nil, fmt.Errorf("merge: stage environment config is required")

View File

@@ -16,18 +16,6 @@ type normalizeStage struct{}
func (normalizeStage) Name() string { return "normalize" } func (normalizeStage) Name() string { return "normalize" }
func (normalizeStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "transcript_polished", Category: "transcripts", RelativePath: "transcripts/polished.json"},
},
Outputs: []artifacts.Ref{
{Kind: "transcript_final", Category: "transcripts", RelativePath: "transcripts/final.json"},
{Kind: "seriatim_normalize_report", Category: "artifacts", RelativePath: "artifacts/seriatim.normalize.report.json"},
},
}
}
func (normalizeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (normalizeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil { if env == nil || env.Config == nil {
return nil, fmt.Errorf("normalize: stage environment config is required") return nil, fmt.Errorf("normalize: stage environment config is required")

View File

@@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/notify" "gitea.maximumdirect.net/eric/narratio/internal/adapters/notify"
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
"gitea.maximumdirect.net/eric/narratio/internal/manifest" "gitea.maximumdirect.net/eric/narratio/internal/manifest"
) )
@@ -17,13 +16,6 @@ type placeholderStage struct {
func (s placeholderStage) Name() string { return s.name } func (s placeholderStage) Name() string { return s.name }
func (s placeholderStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{{Kind: "artifact", Category: "input", RelativePath: s.name + ".input.placeholder"}},
Outputs: []artifacts.Ref{{Kind: "artifact", Category: "output", RelativePath: s.name + ".output.placeholder"}},
}
}
func (s placeholderStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (s placeholderStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
result := &StageResult{ result := &StageResult{
Metadata: map[string]any{ Metadata: map[string]any{

View File

@@ -16,19 +16,6 @@ type polishStage struct{}
func (polishStage) Name() string { return "polish" } func (polishStage) Name() string { return "polish" }
func (polishStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "transcript_base", Category: "transcripts", RelativePath: "transcripts/base.json"},
{Kind: "glossary", Category: "inputs", RelativePath: "inputs/glossary.yml"},
},
Outputs: []artifacts.Ref{
{Kind: "transcript_polished", Category: "transcripts", RelativePath: "transcripts/polished.json"},
{Kind: "audita_report", Category: "artifacts", RelativePath: "artifacts/audita.report.json"},
},
}
}
func (polishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (polishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil { if env == nil || env.Config == nil {
return nil, fmt.Errorf("polish: stage environment config is required") return nil, fmt.Errorf("polish: stage environment config is required")
@@ -101,25 +88,14 @@ func (polishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*St
reportEnabled := env.Config.Pipeline.Audita.Report != nil && *env.Config.Pipeline.Audita.Report reportEnabled := env.Config.Pipeline.Audita.Report != nil && *env.Config.Pipeline.Audita.Report
req := audita.PolishRequest{ req := audita.PolishRequest{
GeneratedConfigPath: generatedConfigPath, GeneratedConfigPath: generatedConfigPath,
MergedTranscriptPath: mergedPath, MergedTranscriptPath: mergedPath,
OutputProcessedPath: processedPath, OutputProcessedPath: processedPath,
GlossaryPath: glossaryPath, GlossaryPath: glossaryPath,
ReportPath: "", ReportPath: "",
WorkDir: workDir, WorkDir: workDir,
Modules: append([]string(nil), env.Config.Pipeline.Audita.Modules...), StdoutLogPath: stdoutPath,
BaseURL: env.Config.Pipeline.Audita.BaseURL, StderrLogPath: stderrPath,
Model: env.Config.Pipeline.Audita.Model,
TranscriptDescription: env.Config.Pipeline.Audita.TranscriptDescription,
ConfigPath: env.Config.Pipeline.Audita.ConfigPath,
OutputSchema: env.Config.Pipeline.Audita.OutputSchema,
WorkDirRetention: env.Config.Pipeline.Audita.WorkDirRetention,
TotalLLMConcurrency: env.Config.Pipeline.Audita.TotalLLMConcurrency,
ProposalLLMConcurrency: env.Config.Pipeline.Audita.ProposalLLMConcurrency,
ValidationModel: env.Config.Pipeline.Audita.ValidationModel,
ValidationLLMConcurrency: env.Config.Pipeline.Audita.ValidationLLMConcurrency,
StdoutLogPath: stdoutPath,
StderrLogPath: stderrPath,
} }
if reportEnabled { if reportEnabled {
req.ReportPath = reportPath req.ReportPath = reportPath
@@ -197,14 +173,14 @@ func (polishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*St
"report_path": reportCanonicalPath, "report_path": reportCanonicalPath,
"audita_work_dir": workDir, "audita_work_dir": workDir,
"report_enabled": reportEnabled, "report_enabled": reportEnabled,
"modules": append([]string(nil), req.Modules...), "modules": append([]string(nil), env.Config.Pipeline.Audita.Modules...),
"base_url": req.BaseURL, "base_url": env.Config.Pipeline.Audita.BaseURL,
"model": req.Model, "model": env.Config.Pipeline.Audita.Model,
"transcript_description": req.TranscriptDescription, "transcript_description": env.Config.Pipeline.Audita.TranscriptDescription,
"config_path": req.ConfigPath, "config_path": env.Config.Pipeline.Audita.ConfigPath,
"output_schema": req.OutputSchema, "output_schema": env.Config.Pipeline.Audita.OutputSchema,
"work_dir_retention": req.WorkDirRetention, "work_dir_retention": env.Config.Pipeline.Audita.WorkDirRetention,
"validation_model": req.ValidationModel, "validation_model": env.Config.Pipeline.Audita.ValidationModel,
"total_llm_concurrency": totalLLMConcurrency, "total_llm_concurrency": totalLLMConcurrency,
"proposal_llm_concurrency": proposalLLMConcurrency, "proposal_llm_concurrency": proposalLLMConcurrency,
"validation_llm_concurrency": validationConcurrency, "validation_llm_concurrency": validationConcurrency,

View File

@@ -48,40 +48,6 @@ func TestPolishStagePolishesMergedTranscriptAndRecordsMetadata(t *testing.T) {
if req.WorkDir != filepath.Join(paths.ArtifactsDir, "audita-work") { if req.WorkDir != filepath.Join(paths.ArtifactsDir, "audita-work") {
t.Fatalf("work dir = %q", req.WorkDir) t.Fatalf("work dir = %q", req.WorkDir)
} }
if strings.Join(req.Modules, ",") != "glossary,homophones,grammar" {
t.Fatalf("modules = %#v", req.Modules)
}
if req.BaseURL != "https://openrouter.ai/api/v1" {
t.Fatalf("base url = %q", req.BaseURL)
}
if req.Model != "openrouter/google/gemma-4-31b-it" {
t.Fatalf("model = %q", req.Model)
}
if req.ValidationModel != "openrouter/google/gemma-4-31b-it" {
t.Fatalf("validation model = %q", req.ValidationModel)
}
if req.TranscriptDescription != "Campaign Session 42" {
t.Fatalf("transcript description = %q", req.TranscriptDescription)
}
if req.ConfigPath != "/etc/audita/config.yml" {
t.Fatalf("config path = %q", req.ConfigPath)
}
if req.OutputSchema != "audita-v1" {
t.Fatalf("output schema = %q", req.OutputSchema)
}
if req.WorkDirRetention != "auto" {
t.Fatalf("work dir retention = %q", req.WorkDirRetention)
}
if req.TotalLLMConcurrency == nil || *req.TotalLLMConcurrency != 3 {
t.Fatalf("total llm concurrency = %#v, want 3", req.TotalLLMConcurrency)
}
if req.ProposalLLMConcurrency == nil || *req.ProposalLLMConcurrency != 2 {
t.Fatalf("proposal llm concurrency = %#v, want 2", req.ProposalLLMConcurrency)
}
if req.ValidationLLMConcurrency == nil || *req.ValidationLLMConcurrency != 2 {
t.Fatalf("validation llm concurrency = %#v, want 2", req.ValidationLLMConcurrency)
}
if len(result.Outputs) != 2 { if len(result.Outputs) != 2 {
t.Fatalf("outputs len = %d, want 2", len(result.Outputs)) t.Fatalf("outputs len = %d, want 2", len(result.Outputs))
} }

View File

@@ -24,22 +24,6 @@ type prepareStage struct{}
func (prepareStage) Name() string { return "prepare" } func (prepareStage) Name() string { return "prepare" }
func (prepareStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "config", Category: "inputs", RelativePath: "campaign.yml"},
{Kind: "config", Category: "inputs", RelativePath: "session.yml"},
{Kind: "config", Category: "inputs", RelativePath: "pipeline.resolved.yml"},
{Kind: "config", Category: "inputs", RelativePath: "speakers.yml"},
{Kind: "config", Category: "inputs", RelativePath: "autocorrect.yml"},
{Kind: "config", Category: "inputs", RelativePath: "glossary.yml"},
{Kind: "config", Category: "inputs", RelativePath: "players.yml"},
{Kind: "config", Category: "inputs", RelativePath: "party.yml"},
{Kind: "audio", Category: "audio", RelativePath: "*.flac"},
},
}
}
func (prepareStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (prepareStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil { if env == nil || env.Config == nil {
return nil, fmt.Errorf("prepare: stage environment config is required") return nil, fmt.Errorf("prepare: stage environment config is required")

View File

@@ -43,14 +43,6 @@ var publishPrerequisiteStages = []string{
func (publishStage) Name() string { return "publish" } func (publishStage) Name() string { return "publish" }
func (publishStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "manifest", Category: "input", RelativePath: "manifest.json"},
},
}
}
func (publishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (publishStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil || env.Config.Pipeline == nil || env.Config.Session == nil { if env == nil || env.Config == nil || env.Config.Pipeline == nil || env.Config.Session == nil {
return nil, fmt.Errorf("publish: resolved config must include pipeline and session") return nil, fmt.Errorf("publish: resolved config must include pipeline and session")
@@ -671,24 +663,6 @@ func resolvePublishRunManifestPath(env *Env, m *manifest.Manifest) (string, erro
return canonical, nil return canonical, nil
} }
func resolvePublishSessionRoot(env *Env, m *manifest.Manifest) (string, error) {
sessionID := strings.TrimSpace(env.Config.Session.SessionID)
if sessionID == "" && m != nil {
sessionID = strings.TrimSpace(m.SessionID)
}
campaign := strings.TrimSpace(env.Config.Session.Campaign)
if campaign == "" && m != nil {
campaign = strings.TrimSpace(m.Campaign)
}
if sessionID == "" {
return "", fmt.Errorf("session id is required")
}
if campaign == "" {
return "", fmt.Errorf("campaign is required")
}
return filepath.Clean(artifacts.SessionWorkDirForCampaign(env.Config.Pipeline.Workspace.Root, campaign, sessionID)), nil
}
func publishSessionPaths(env *Env, m *manifest.Manifest) artifacts.SessionPaths { func publishSessionPaths(env *Env, m *manifest.Manifest) artifacts.SessionPaths {
sessionID := strings.TrimSpace(env.Config.Session.SessionID) sessionID := strings.TrimSpace(env.Config.Session.SessionID)
if sessionID == "" && m != nil { if sessionID == "" && m != nil {

View File

@@ -17,19 +17,6 @@ type renderStage struct{}
func (renderStage) Name() string { return "render" } func (renderStage) Name() string { return "render" }
func (renderStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "transcript_final", Category: "transcripts", RelativePath: "transcripts/final.json"},
{Kind: "transcript_final_trimmed", Category: "transcripts", RelativePath: "transcripts/final.trimmed.json"},
},
Outputs: []artifacts.Ref{
{Kind: artifacts.TranscriptOutputKindFinalMarkdown, Category: "transcripts", RelativePath: artifacts.TranscriptPathFinalMarkdown},
{Kind: artifacts.TranscriptOutputKindFinalTrimmedMarkdown, Category: "transcripts", RelativePath: artifacts.TranscriptPathFinalTrimmedMarkdown},
},
}
}
func (renderStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (renderStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil { if env == nil || env.Config == nil {
return nil, fmt.Errorf("render: stage environment config is required") return nil, fmt.Errorf("render: stage environment config is required")

View File

@@ -40,16 +40,9 @@ type Env struct {
RevalidatePublishLocks func(context.Context) ([]config.PublishLockRule, error) RevalidatePublishLocks func(context.Context) ([]config.PublishLockRule, error)
} }
// IODecl declares the intended input/output artifact kinds for a stage.
type IODecl struct {
Inputs []artifacts.Ref
Outputs []artifacts.Ref
}
// Stage is the pipeline unit contract. // Stage is the pipeline unit contract.
type Stage interface { type Stage interface {
Name() string Name() string
Declares() IODecl
Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error)
} }

View File

@@ -19,17 +19,6 @@ type transcribeStage struct{}
func (transcribeStage) Name() string { return "transcribe" } func (transcribeStage) Name() string { return "transcribe" }
func (transcribeStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "audio", Category: "audio", RelativePath: "audio/*.flac"},
},
Outputs: []artifacts.Ref{
{Kind: "transcript_raw", Category: "transcripts", RelativePath: "transcripts/raw/*.json"},
},
}
}
func (transcribeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (transcribeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil { if env == nil || env.Config == nil {
return nil, fmt.Errorf("transcribe: stage environment config is required") return nil, fmt.Errorf("transcribe: stage environment config is required")

View File

@@ -20,18 +20,6 @@ type trimStage struct{}
func (trimStage) Name() string { return "trim" } func (trimStage) Name() string { return "trim" }
func (trimStage) Declares() IODecl {
return IODecl{
Inputs: []artifacts.Ref{
{Kind: "transcript_final", Category: "transcripts", RelativePath: "transcripts/final.json"},
},
Outputs: []artifacts.Ref{
{Kind: "transcript_final_trimmed", Category: "transcripts", RelativePath: "transcripts/final.trimmed.json"},
{Kind: "session_bounds", Category: "artifacts", RelativePath: "artifacts/session_bounds.json"},
},
}
}
func (trimStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) { func (trimStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*StageResult, error) {
if env == nil || env.Config == nil { if env == nil || env.Config == nil {
return nil, fmt.Errorf("trim: stage environment config is required") return nil, fmt.Errorf("trim: stage environment config is required")