diff --git a/internal/stage/run_local.go b/internal/stage/run_local.go index 682bd22..760907c 100644 --- a/internal/stage/run_local.go +++ b/internal/stage/run_local.go @@ -99,7 +99,11 @@ func runLocalPathForCanonical(layout runStageLayout, sessionPaths artifacts.Sess if rel == "." || rel == ".." || strings.HasPrefix(rel, ".."+string(filepath.Separator)) { return "", fmt.Errorf("canonical path %q is outside session root %q", cleanCanonical, sessionPaths.Root) } - return filepath.Join(layout.OutputsDir, rel), nil + localPath := filepath.Join(layout.OutputsDir, rel) + if err := os.MkdirAll(filepath.Dir(localPath), 0o755); err != nil { + return "", fmt.Errorf("create run-local output parent for %q: %w", localPath, err) + } + return localPath, nil } func promoteRunLocalOutput( diff --git a/internal/stage/run_local_test.go b/internal/stage/run_local_test.go new file mode 100644 index 0000000..18f6ee4 --- /dev/null +++ b/internal/stage/run_local_test.go @@ -0,0 +1,35 @@ +package stage + +import ( + "os" + "path/filepath" + "testing" + + "gitea.maximumdirect.net/eric/narratio/internal/artifacts" +) + +func TestRunLocalPathForCanonicalCreatesParentDirectories(t *testing.T) { + root := t.TempDir() + sessionRoot := filepath.Join(root, "work", "dilfs", "2026-05-17") + layout := runStageLayout{ + Enabled: true, + OutputsDir: filepath.Join(sessionRoot, "runs", "run-1", "merge", "outputs"), + } + if err := os.MkdirAll(layout.OutputsDir, 0o755); err != nil { + t.Fatalf("mkdir outputs dir: %v", err) + } + + canonical := filepath.Join(sessionRoot, "transcripts", "merged.json") + got, err := runLocalPathForCanonical(layout, artifacts.SessionPaths{Root: sessionRoot}, canonical) + if err != nil { + t.Fatalf("runLocalPathForCanonical() error = %v", err) + } + + want := filepath.Join(layout.OutputsDir, "transcripts", "merged.json") + if got != want { + t.Fatalf("runLocalPathForCanonical() = %q, want %q", got, want) + } + if _, err := os.Stat(filepath.Dir(got)); err != nil { + t.Fatalf("expected run-local parent directory to exist: %v", err) + } +}