Implement real Audita polish stage

This commit is contained in:
2026-05-04 08:05:27 -05:00
parent 28c7ab3287
commit de11651528
8 changed files with 677 additions and 22 deletions

View File

@@ -197,7 +197,10 @@ func writeValidConfigFiles(t *testing.T, workspaceRoot string, transcribeURL ...
url = transcribeURL[0]
}
seriatimBinary := writeSeriatimAppTestWrapper(t)
auditaBinary := writeAuditaAppTestWrapper(t)
t.Setenv("GO_WANT_APP_SERIATIM_HELPER", "1")
t.Setenv("GO_WANT_APP_AUDITA_HELPER", "1")
t.Setenv("AUDITA_LLM_API_KEY", "test-audita-key")
pipelineYAML := `workspace:
root: ` + workspaceRoot + `
@@ -216,7 +219,7 @@ seriatim:
coalesce_gap: 3.0
report: true
audita:
binary: audita
binary: ` + auditaBinary + `
analyzer:
timeout: 20m
artifacts:
@@ -335,6 +338,75 @@ func TestSeriatimAppHelper(t *testing.T) {
os.Exit(0)
}
func writeAuditaAppTestWrapper(t *testing.T) string {
t.Helper()
exe, err := os.Executable()
if err != nil {
t.Fatalf("os.Executable() error = %v", err)
}
path := filepath.Join(t.TempDir(), "audita-helper-wrapper.sh")
content := "#!/bin/sh\nexec \"" + exe + "\" -test.run=TestAuditaAppHelper -- \"$@\"\n"
if err := os.WriteFile(path, []byte(content), 0o755); err != nil {
t.Fatalf("WriteFile(%q): %v", path, err)
}
return path
}
func TestAuditaAppHelper(t *testing.T) {
if os.Getenv("GO_WANT_APP_AUDITA_HELPER") != "1" {
return
}
args := os.Args
start := -1
for i := range args {
if args[i] == "--" {
start = i + 1
break
}
}
if start < 0 || start >= len(args) {
_, _ = os.Stderr.WriteString("missing -- args separator\n")
os.Exit(2)
}
processArgs := args[start:]
outputPath := appSeriatimFlagValue(processArgs, "--output")
reportPath := appSeriatimFlagValue(processArgs, "--report-json")
workDir := appSeriatimFlagValue(processArgs, "--work-dir")
if strings.TrimSpace(outputPath) == "" {
_, _ = os.Stderr.WriteString("missing --output\n")
os.Exit(2)
}
if err := os.MkdirAll(filepath.Dir(outputPath), 0o755); err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("mkdir output dir: %v\n", err))
os.Exit(2)
}
if err := os.WriteFile(outputPath, []byte(`{"schema":"audita.processed.v1","segments":[]}`), 0o644); err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("write output: %v\n", err))
os.Exit(2)
}
if strings.TrimSpace(reportPath) != "" {
if err := os.MkdirAll(filepath.Dir(reportPath), 0o755); err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("mkdir report dir: %v\n", err))
os.Exit(2)
}
if err := os.WriteFile(reportPath, []byte(`{"report":true}`), 0o644); err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("write report: %v\n", err))
os.Exit(2)
}
}
if strings.TrimSpace(workDir) != "" {
if err := os.MkdirAll(workDir, 0o755); err != nil {
_, _ = os.Stderr.WriteString(fmt.Sprintf("mkdir work dir: %v\n", err))
os.Exit(2)
}
}
_, _ = os.Stdout.WriteString("audita helper stdout\n")
_, _ = os.Stderr.WriteString("audita helper stderr\n")
os.Exit(0)
}
func appSeriatimFlagValue(args []string, name string) string {
for i := 0; i < len(args)-1; i++ {
if args[i] == name {

View File

@@ -29,6 +29,7 @@ func TestResumeStartsAfterCompletedStages(t *testing.T) {
mustWriteTestFile(t, filepath.Join(workRoot, "transcripts", "raw", "alice.json"), `{"segments":[]}`)
mustWriteTestFile(t, filepath.Join(workRoot, "inputs", "speakers.yml"), "match:\n - speaker: Alice\n match: [\"alice\"]\n")
mustWriteTestFile(t, filepath.Join(workRoot, "inputs", "autocorrect.yml"), "[]\n")
mustWriteTestFile(t, filepath.Join(workRoot, "inputs", "glossary.yml"), "terms: []\n")
var out bytes.Buffer
err := Resume(context.Background(), []string{"--config", pipelinePath, "--session", sessionPath}, &out)
@@ -105,6 +106,9 @@ func TestRunStageExecutesOnlySelectedStage(t *testing.T) {
workspaceRoot := t.TempDir()
pipelinePath, sessionPath := writeValidConfigFiles(t, workspaceRoot)
manifestPath := filepath.Join(workspaceRoot, "work", "2026-05-03", "manifest.json")
workRoot := filepath.Join(workspaceRoot, "work", "2026-05-03")
mustWriteTestFile(t, filepath.Join(workRoot, "transcripts", "merged.json"), `{"segments":[]}`)
mustWriteTestFile(t, filepath.Join(workRoot, "inputs", "glossary.yml"), "terms: []\n")
var out bytes.Buffer
err := RunStage(context.Background(), []string{"--config", pipelinePath, "--session", sessionPath, "polish"}, &out)
@@ -132,6 +136,9 @@ func TestRunStageSkipAndForce(t *testing.T) {
workspaceRoot := t.TempDir()
pipelinePath, sessionPath := writeValidConfigFiles(t, workspaceRoot)
manifestPath := filepath.Join(workspaceRoot, "work", "2026-05-03", "manifest.json")
workRoot := filepath.Join(workspaceRoot, "work", "2026-05-03")
mustWriteTestFile(t, filepath.Join(workRoot, "transcripts", "merged.json"), `{"segments":[]}`)
mustWriteTestFile(t, filepath.Join(workRoot, "inputs", "glossary.yml"), "terms: []\n")
store := &manifest.LocalStore{}
m := manifest.New("2026-05-03", time.Date(2026, 5, 3, 10, 0, 0, 0, time.UTC))

View File

@@ -66,7 +66,11 @@ func executeStages(ctx context.Context, cfg *config.Config, stages []stage.Stage
env.Seriatim = runner
}
if env.Audita == nil {
env.Audita = &audita.NoopRunner{}
runner, err := buildDefaultAuditaRunner(env.Config)
if err != nil {
return nil, fmt.Errorf("initialize audita runner: %w", err)
}
env.Audita = runner
}
if env.Analyzer == nil {
env.Analyzer = &analyzer.NoopRunner{}
@@ -217,6 +221,40 @@ func buildDefaultSeriatimRunner(cfg *config.Config) (seriatim.Runner, error) {
return runner, nil
}
func buildDefaultAuditaRunner(cfg *config.Config) (audita.Runner, error) {
if cfg == nil || cfg.Pipeline == nil {
return &audita.NoopRunner{}, nil
}
a := cfg.Pipeline.Audita
if strings.TrimSpace(a.Binary) == "" || strings.TrimSpace(a.Timeout) == "" || strings.TrimSpace(a.LLMAPIKeyEnv) == "" || len(a.Modules) == 0 || strings.TrimSpace(a.BaseURL) == "" || strings.TrimSpace(a.Model) == "" {
// Compatibility fallback for tests or internal call paths that bypass config validation/defaults.
return &audita.NoopRunner{}, nil
}
report := false
if a.Report != nil {
report = *a.Report
}
runner, err := audita.NewSubprocessRunnerFromConfigValues(
a.Binary,
a.Timeout,
a.LLMAPIKeyEnv,
append([]string(nil), a.Modules...),
a.BaseURL,
a.Model,
a.LLMConcurrency,
a.ValidationModel,
a.ValidationLLMConcurrency,
report,
)
if err != nil {
return nil, fmt.Errorf("from pipeline.audita: %w", err)
}
return runner, nil
}
func loadOrCreateManifest(ctx context.Context, store manifest.Store, path, sessionID string) (*manifest.Manifest, error) {
exists, err := fileExists(path)
if err != nil {

View File

@@ -99,6 +99,21 @@ func TestExecuteStagesPlaceholderSuccessUpdatesManifest(t *testing.T) {
}
continue
}
if name == "polish" {
if sr.Metadata == nil || sr.Metadata["stage"] != "polish" {
t.Fatalf("polish metadata missing stage=polish: %#v", sr.Metadata)
}
if len(sr.Outputs) == 0 {
t.Fatalf("polish outputs missing")
}
if len(sr.Logs) == 0 {
t.Fatalf("polish logs missing")
}
if len(sr.GeneratedConfigs) == 0 {
t.Fatalf("polish generated configs missing")
}
continue
}
if sr.Metadata == nil || sr.Metadata["placeholder"] != true {
t.Fatalf("stage %q missing placeholder metadata", name)
}
@@ -320,6 +335,18 @@ func TestAdapterBackedStageFailureMarksManifestFailed(t *testing.T) {
t.Fatalf("write autocorrect: %v", err)
}
}
if tc.name == "polish" {
paths, ensureErr := artifactStore.EnsureLayout(cfg.Session.SessionID)
if ensureErr != nil {
t.Fatalf("EnsureLayout() error = %v", ensureErr)
}
if err := os.WriteFile(filepath.Join(paths.TranscriptsDir, "merged.json"), []byte(`{"segments":[]}`), 0o644); err != nil {
t.Fatalf("write merged transcript: %v", err)
}
if err := os.WriteFile(filepath.Join(paths.InputsDir, "glossary.yml"), []byte("terms: []\n"), 0o644); err != nil {
t.Fatalf("write glossary: %v", err)
}
}
_, runErr := executeStages(context.Background(), cfg, []stage.Stage{selected}, RunOptions{Env: tc.env})
if runErr == nil {