package audita import ( "context" "encoding/json" "fmt" "path/filepath" "gitea.maximumdirect.net/eric/narratio/internal/adapters/subprocess" "gitea.maximumdirect.net/eric/narratio/internal/fileops" ) // NoopRunner is a deterministic no-op audita adapter. type NoopRunner struct{} // Run returns requested output path with placeholder metadata. func (n *NoopRunner) Run(ctx context.Context, req PolishRequest) (PolishResult, error) { if err := ctx.Err(); err != nil { return PolishResult{}, err } if err := materializePlaceholders(req); err != nil { return PolishResult{}, err } return PolishResult{ ProcessedTranscriptPath: req.OutputProcessedPath, ReportPath: req.ReportPath, WorkDir: req.WorkDir, StdoutLogPath: req.StdoutLogPath, StderrLogPath: req.StderrLogPath, GeneratedConfigPath: req.GeneratedConfigPath, Metadata: map[string]any{"placeholder": true}, }, nil } // FakeRunner captures polish requests and returns deterministic responses. type FakeRunner struct { Requests []PolishRequest Err error Result PolishResult } // Run records request and returns configured response. func (f *FakeRunner) Run(ctx context.Context, req PolishRequest) (PolishResult, error) { if err := ctx.Err(); err != nil { return PolishResult{}, err } f.Requests = append(f.Requests, req) if f.Err != nil { return PolishResult{}, f.Err } if err := materializePlaceholders(req); err != nil { return PolishResult{}, err } res := f.Result if res.ProcessedTranscriptPath == "" { res.ProcessedTranscriptPath = req.OutputProcessedPath } if res.ReportPath == "" { res.ReportPath = req.ReportPath } if res.WorkDir == "" { res.WorkDir = req.WorkDir } if res.StdoutLogPath == "" { res.StdoutLogPath = req.StdoutLogPath } if res.StderrLogPath == "" { res.StderrLogPath = req.StderrLogPath } if res.GeneratedConfigPath == "" { res.GeneratedConfigPath = req.GeneratedConfigPath } if res.Metadata == nil { res.Metadata = map[string]any{"fake": true} } return res, nil } func materializePlaceholders(req PolishRequest) error { if req.GeneratedConfigPath != "" { payload := map[string]any{ "schema": "audita.generated.v1", "placeholder": true, "merged_transcript_path": req.MergedTranscriptPath, "output_path": req.OutputProcessedPath, } if err := subprocess.WriteYAMLAtomic(req.GeneratedConfigPath, payload, fileops.WorkspaceFileMode); err != nil { return fmt.Errorf("write generated config %q: %w", req.GeneratedConfigPath, err) } } if req.StdoutLogPath != "" { if err := subprocess.WriteFileAtomic(req.StdoutLogPath, []byte("audita noop/fake stdout placeholder\n"), fileops.WorkspaceFileMode); err != nil { return fmt.Errorf("write stdout log %q: %w", req.StdoutLogPath, err) } } if req.StderrLogPath != "" { if err := subprocess.WriteFileAtomic(req.StderrLogPath, []byte("audita noop/fake stderr placeholder\n"), fileops.WorkspaceFileMode); err != nil { return fmt.Errorf("write stderr log %q: %w", req.StderrLogPath, err) } } if err := writeJSONIfRequested(req.OutputProcessedPath, map[string]any{ "schema": "audita.processed.v1", "segments": []any{}, }); err != nil { return err } if err := writeJSONIfRequested(req.ReportPath, map[string]any{ "schema": "audita.report.v1", "steps": []any{}, }); err != nil { return err } return nil } func writeJSONIfRequested(path string, payload any) error { if path == "" { return nil } if err := fileops.EnsureWorkspaceDirectory(filepath.Dir(path)); err != nil { return fmt.Errorf("create parent directory %q: %w", filepath.Dir(path), err) } data, err := json.Marshal(payload) if err != nil { return fmt.Errorf("marshal placeholder json for %q: %w", path, err) } if err := subprocess.WriteFileAtomic(path, data, fileops.WorkspaceFileMode); err != nil { return fmt.Errorf("write placeholder json %q: %w", path, err) } return nil }