Replace normalize stage with trim scaffold
This commit is contained in:
@@ -17,7 +17,7 @@ Implemented now:
|
|||||||
|
|
||||||
Not implemented yet:
|
Not implemented yet:
|
||||||
|
|
||||||
- real `normalize` behavior
|
- real `trim` behavior
|
||||||
- real `archive` behavior
|
- real `archive` behavior
|
||||||
- real `notify` behavior
|
- real `notify` behavior
|
||||||
- additional analyze artifacts beyond `session_recap`
|
- additional analyze artifacts beyond `session_recap`
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ Implemented:
|
|||||||
|
|
||||||
Still placeholder/future:
|
Still placeholder/future:
|
||||||
|
|
||||||
- `normalize` stage behavior
|
- `trim` stage behavior
|
||||||
- `archive` stage behavior
|
- `archive` stage behavior
|
||||||
- `notify` stage behavior
|
- `notify` stage behavior
|
||||||
- additional Scriptorium artifact types beyond `session_recap`
|
- additional Scriptorium artifact types beyond `session_recap`
|
||||||
@@ -36,9 +36,9 @@ Canonical stage order:
|
|||||||
|
|
||||||
1. `prepare`
|
1. `prepare`
|
||||||
2. `transcribe`
|
2. `transcribe`
|
||||||
3. `normalize`
|
3. `merge`
|
||||||
4. `merge`
|
4. `polish`
|
||||||
5. `polish`
|
5. `trim`
|
||||||
6. `analyze`
|
6. `analyze`
|
||||||
7. `archive`
|
7. `archive`
|
||||||
8. `notify`
|
8. `notify`
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func TestExecuteValidCommands(t *testing.T) {
|
|||||||
wantOut string
|
wantOut string
|
||||||
}{
|
}{
|
||||||
{name: "run", args: []string{"run", "--config", pipelinePath, "--session", sessionPath}, wantOut: "narratio run: session 2026-05-03; executed=8 skipped=0; manifest="},
|
{name: "run", args: []string{"run", "--config", pipelinePath, "--session", sessionPath}, wantOut: "narratio run: session 2026-05-03; executed=8 skipped=0; manifest="},
|
||||||
{name: "plan", args: []string{"plan", "--config", pipelinePath, "--session", sessionPath}, wantOut: "prepare: skip\ntranscribe: skip\nnormalize: skip\nmerge: skip\npolish: skip\nanalyze: skip\narchive: skip\nnotify: skip"},
|
{name: "plan", args: []string{"plan", "--config", pipelinePath, "--session", sessionPath}, wantOut: "prepare: skip\ntranscribe: skip\nmerge: skip\npolish: skip\ntrim: skip\nanalyze: skip\narchive: skip\nnotify: skip"},
|
||||||
{name: "status", args: []string{"status", "--manifest", manifestPath}, wantOut: "session_id: 2026-05-03"},
|
{name: "status", args: []string{"status", "--manifest", manifestPath}, wantOut: "session_id: 2026-05-03"},
|
||||||
{name: "resume", args: []string{"resume", "--config", pipelinePath, "--session", sessionPath}, wantOut: "narratio resume: session 2026-05-03 has no remaining stages"},
|
{name: "resume", args: []string{"resume", "--config", pipelinePath, "--session", sessionPath}, wantOut: "narratio resume: session 2026-05-03 has no remaining stages"},
|
||||||
{name: "run-stage", args: []string{"run-stage", "--config", pipelinePath, "--session", sessionPath, "polish"}, wantOut: "narratio run-stage: stage=polish executed=0 skipped=1 force=false; manifest="},
|
{name: "run-stage", args: []string{"run-stage", "--config", pipelinePath, "--session", sessionPath, "polish"}, wantOut: "narratio run-stage: stage=polish executed=0 skipped=1 force=false; manifest="},
|
||||||
@@ -106,6 +106,22 @@ func TestExecuteRunStageUnknownFails(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestExecuteRunStageNormalizeIsRejected(t *testing.T) {
|
||||||
|
workspaceRoot := t.TempDir()
|
||||||
|
pipelinePath, sessionPath := writeValidConfigFiles(t, workspaceRoot, "https://example.com/transcribe")
|
||||||
|
|
||||||
|
var stdout bytes.Buffer
|
||||||
|
var stderr bytes.Buffer
|
||||||
|
|
||||||
|
code := Execute([]string{"run-stage", "--config", pipelinePath, "--session", sessionPath, "normalize"}, &stdout, &stderr)
|
||||||
|
if code == 0 {
|
||||||
|
t.Fatal("exit code = 0, want non-zero")
|
||||||
|
}
|
||||||
|
if !strings.Contains(stderr.String(), "unknown stage") {
|
||||||
|
t.Fatalf("stderr = %q, want unknown stage error", stderr.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestExecuteRunStageTranscribeUsesConfiguredWhisperXServer(t *testing.T) {
|
func TestExecuteRunStageTranscribeUsesConfiguredWhisperXServer(t *testing.T) {
|
||||||
workspaceRoot := t.TempDir()
|
workspaceRoot := t.TempDir()
|
||||||
var serverCalls int
|
var serverCalls int
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ func TestPlanCreatesAndReusesWorkdir(t *testing.T) {
|
|||||||
if !strings.Contains(got, "narratio plan: workdir prepared at") {
|
if !strings.Contains(got, "narratio plan: workdir prepared at") {
|
||||||
t.Fatalf("first output = %q, want workdir prepared", got)
|
t.Fatalf("first output = %q, want workdir prepared", got)
|
||||||
}
|
}
|
||||||
for _, name := range []string{"prepare", "transcribe", "normalize", "merge", "polish", "analyze", "archive", "notify"} {
|
for _, name := range []string{"prepare", "transcribe", "merge", "polish", "trim", "analyze", "archive", "notify"} {
|
||||||
if !strings.Contains(got, name+": run") {
|
if !strings.Contains(got, name+": run") {
|
||||||
t.Fatalf("first output = %q, missing stage %q", got, name)
|
t.Fatalf("first output = %q, missing stage %q", got, name)
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ func TestPlanCreatesAndReusesWorkdir(t *testing.T) {
|
|||||||
filepath.Join(sessionWorkdir, "inputs"),
|
filepath.Join(sessionWorkdir, "inputs"),
|
||||||
filepath.Join(sessionWorkdir, "audio"),
|
filepath.Join(sessionWorkdir, "audio"),
|
||||||
filepath.Join(sessionWorkdir, "transcripts", "raw"),
|
filepath.Join(sessionWorkdir, "transcripts", "raw"),
|
||||||
filepath.Join(sessionWorkdir, "transcripts", "normalized"),
|
filepath.Join(sessionWorkdir, "transcripts", "trimmed"),
|
||||||
filepath.Join(sessionWorkdir, "artifacts"),
|
filepath.Join(sessionWorkdir, "artifacts"),
|
||||||
filepath.Join(sessionWorkdir, "config"),
|
filepath.Join(sessionWorkdir, "config"),
|
||||||
filepath.Join(sessionWorkdir, "logs"),
|
filepath.Join(sessionWorkdir, "logs"),
|
||||||
@@ -81,8 +81,8 @@ func TestPlanShowsRunAndSkipFromManifest(t *testing.T) {
|
|||||||
if !strings.Contains(got, "prepare: skip") || !strings.Contains(got, "transcribe: skip") {
|
if !strings.Contains(got, "prepare: skip") || !strings.Contains(got, "transcribe: skip") {
|
||||||
t.Fatalf("output = %q, want prepare/transcribe skipped", got)
|
t.Fatalf("output = %q, want prepare/transcribe skipped", got)
|
||||||
}
|
}
|
||||||
if !strings.Contains(got, "normalize: run") {
|
if !strings.Contains(got, "trim: run") {
|
||||||
t.Fatalf("output = %q, want normalize run", got)
|
t.Fatalf("output = %q, want trim run", got)
|
||||||
}
|
}
|
||||||
if !strings.Contains(got, "totals: run=6 skip=2") {
|
if !strings.Contains(got, "totals: run=6 skip=2") {
|
||||||
t.Fatalf("output = %q, want totals run=6 skip=2", got)
|
t.Fatalf("output = %q, want totals run=6 skip=2", got)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import "testing"
|
|||||||
|
|
||||||
func TestBuildFullPlanOrder(t *testing.T) {
|
func TestBuildFullPlanOrder(t *testing.T) {
|
||||||
got := BuildFullPlan()
|
got := BuildFullPlan()
|
||||||
want := []string{"prepare", "transcribe", "normalize", "merge", "polish", "analyze", "archive", "notify"}
|
want := []string{"prepare", "transcribe", "merge", "polish", "trim", "analyze", "archive", "notify"}
|
||||||
if len(got) != len(want) {
|
if len(got) != len(want) {
|
||||||
t.Fatalf("len(plan) = %d, want %d", len(got), len(want))
|
t.Fatalf("len(plan) = %d, want %d", len(got), len(want))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ func TestResumeStartsAfterCompletedStages(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("load manifest: %v", err)
|
t.Fatalf("load manifest: %v", err)
|
||||||
}
|
}
|
||||||
if loaded.Stages["normalize"] == nil || loaded.Stages["normalize"].Status != manifest.StatusSucceeded {
|
if loaded.Stages["trim"] == nil || loaded.Stages["trim"].Status != manifest.StatusSucceeded {
|
||||||
t.Fatalf("normalize stage = %#v, want succeeded", loaded.Stages["normalize"])
|
t.Fatalf("trim stage = %#v, want succeeded", loaded.Stages["trim"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ func TestResumeNoRemainingStages(t *testing.T) {
|
|||||||
|
|
||||||
store := &manifest.LocalStore{}
|
store := &manifest.LocalStore{}
|
||||||
m := manifest.New("2026-05-03", time.Date(2026, 5, 3, 10, 0, 0, 0, time.UTC))
|
m := manifest.New("2026-05-03", time.Date(2026, 5, 3, 10, 0, 0, 0, time.UTC))
|
||||||
for _, name := range []string{"prepare", "transcribe", "normalize", "merge", "polish", "analyze", "archive", "notify"} {
|
for _, name := range []string{"prepare", "transcribe", "merge", "polish", "trim", "analyze", "archive", "notify"} {
|
||||||
m.MarkStageSucceeded(name, time.Date(2026, 5, 3, 10, 1, 0, 0, time.UTC), nil)
|
m.MarkStageSucceeded(name, time.Date(2026, 5, 3, 10, 1, 0, 0, time.UTC), nil)
|
||||||
}
|
}
|
||||||
if err := store.Save(context.Background(), manifestPath, m); err != nil {
|
if err := store.Save(context.Background(), manifestPath, m); err != nil {
|
||||||
@@ -85,7 +85,7 @@ func TestResumeForceRerunsSucceeded(t *testing.T) {
|
|||||||
|
|
||||||
store := &manifest.LocalStore{}
|
store := &manifest.LocalStore{}
|
||||||
m := manifest.New("2026-05-03", time.Date(2026, 5, 3, 10, 0, 0, 0, time.UTC))
|
m := manifest.New("2026-05-03", time.Date(2026, 5, 3, 10, 0, 0, 0, time.UTC))
|
||||||
for _, name := range []string{"prepare", "transcribe", "normalize", "merge", "polish", "analyze", "archive", "notify"} {
|
for _, name := range []string{"prepare", "transcribe", "merge", "polish", "trim", "analyze", "archive", "notify"} {
|
||||||
m.MarkStageSucceeded(name, time.Date(2026, 5, 3, 10, 1, 0, 0, time.UTC), nil)
|
m.MarkStageSucceeded(name, time.Date(2026, 5, 3, 10, 1, 0, 0, time.UTC), nil)
|
||||||
}
|
}
|
||||||
if err := store.Save(context.Background(), manifestPath, m); err != nil {
|
if err := store.Save(context.Background(), manifestPath, m); err != nil {
|
||||||
@@ -165,3 +165,30 @@ func TestRunStageSkipAndForce(t *testing.T) {
|
|||||||
t.Fatalf("output = %q, want force rerun", out.String())
|
t.Fatalf("output = %q, want force rerun", out.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRunStageTrimPlaceholderExecutes(t *testing.T) {
|
||||||
|
workspaceRoot := t.TempDir()
|
||||||
|
pipelinePath, sessionPath := writeValidConfigFiles(t, workspaceRoot)
|
||||||
|
manifestPath := filepath.Join(workspaceRoot, "work", "2026-05-03", "manifest.json")
|
||||||
|
|
||||||
|
var out bytes.Buffer
|
||||||
|
err := RunStage(context.Background(), []string{"--config", pipelinePath, "--session", sessionPath, "trim"}, &out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("RunStage(trim) error = %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(out.String(), "stage=trim executed=1 skipped=0") {
|
||||||
|
t.Fatalf("output = %q, want stage=trim executed", out.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
store := &manifest.LocalStore{}
|
||||||
|
m, err := store.Load(context.Background(), manifestPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("load manifest: %v", err)
|
||||||
|
}
|
||||||
|
if m.Stages["trim"] == nil || m.Stages["trim"].Status != manifest.StatusSucceeded {
|
||||||
|
t.Fatalf("trim stage = %#v, want succeeded", m.Stages["trim"])
|
||||||
|
}
|
||||||
|
if m.Stages["trim"].Metadata == nil || m.Stages["trim"].Metadata["placeholder"] != true {
|
||||||
|
t.Fatalf("trim stage metadata = %#v, want placeholder=true", m.Stages["trim"].Metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ func TestExecuteStagesPlaceholderSuccessUpdatesManifest(t *testing.T) {
|
|||||||
t.Fatalf("Load manifest error = %v", err)
|
t.Fatalf("Load manifest error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, name := range []string{"prepare", "transcribe", "normalize", "merge", "polish", "analyze", "archive", "notify"} {
|
for _, name := range []string{"prepare", "transcribe", "merge", "polish", "trim", "analyze", "archive", "notify"} {
|
||||||
sr := m.Stages[name]
|
sr := m.Stages[name]
|
||||||
if sr == nil {
|
if sr == nil {
|
||||||
t.Fatalf("missing stage record %q", name)
|
t.Fatalf("missing stage record %q", name)
|
||||||
@@ -238,8 +238,8 @@ func TestExecuteStagesFailureUpdatesManifest(t *testing.T) {
|
|||||||
if got := m.Stages["transcribe"]; got == nil || got.Status != manifest.StatusFailed {
|
if got := m.Stages["transcribe"]; got == nil || got.Status != manifest.StatusFailed {
|
||||||
t.Fatalf("transcribe status = %#v, want failed", got)
|
t.Fatalf("transcribe status = %#v, want failed", got)
|
||||||
}
|
}
|
||||||
if got := m.Stages["normalize"]; got != nil {
|
if got := m.Stages["merge"]; got != nil {
|
||||||
t.Fatalf("normalize should not run, got %#v", got)
|
t.Fatalf("merge should not run, got %#v", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ func (s *LocalStore) EnsureLayout(sessionID string) (SessionPaths, error) {
|
|||||||
paths.AudioDir,
|
paths.AudioDir,
|
||||||
paths.TranscriptsDir,
|
paths.TranscriptsDir,
|
||||||
paths.TranscriptsRawDir,
|
paths.TranscriptsRawDir,
|
||||||
paths.TranscriptsNormalizedDir,
|
paths.TranscriptsTrimmedDir,
|
||||||
paths.ArtifactsDir,
|
paths.ArtifactsDir,
|
||||||
paths.ConfigDir,
|
paths.ConfigDir,
|
||||||
paths.LogsDir,
|
paths.LogsDir,
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ func TestEnsureLayoutCreatesExpectedDirectories(t *testing.T) {
|
|||||||
checkDirExists(t, paths.AudioDir)
|
checkDirExists(t, paths.AudioDir)
|
||||||
checkDirExists(t, paths.TranscriptsDir)
|
checkDirExists(t, paths.TranscriptsDir)
|
||||||
checkDirExists(t, paths.TranscriptsRawDir)
|
checkDirExists(t, paths.TranscriptsRawDir)
|
||||||
checkDirExists(t, paths.TranscriptsNormalizedDir)
|
checkDirExists(t, paths.TranscriptsTrimmedDir)
|
||||||
checkDirExists(t, paths.ArtifactsDir)
|
checkDirExists(t, paths.ArtifactsDir)
|
||||||
checkDirExists(t, paths.ConfigDir)
|
checkDirExists(t, paths.ConfigDir)
|
||||||
checkDirExists(t, paths.LogsDir)
|
checkDirExists(t, paths.LogsDir)
|
||||||
|
|||||||
@@ -4,18 +4,18 @@ import "path/filepath"
|
|||||||
|
|
||||||
// SessionPaths contains canonical local paths for one session work directory.
|
// SessionPaths contains canonical local paths for one session work directory.
|
||||||
type SessionPaths struct {
|
type SessionPaths struct {
|
||||||
WorkspaceRoot string
|
WorkspaceRoot string
|
||||||
Root string
|
Root string
|
||||||
InputsDir string
|
InputsDir string
|
||||||
AudioDir string
|
AudioDir string
|
||||||
TranscriptsDir string
|
TranscriptsDir string
|
||||||
TranscriptsRawDir string
|
TranscriptsRawDir string
|
||||||
TranscriptsNormalizedDir string
|
TranscriptsTrimmedDir string
|
||||||
ArtifactsDir string
|
ArtifactsDir string
|
||||||
ConfigDir string
|
ConfigDir string
|
||||||
LogsDir string
|
LogsDir string
|
||||||
ManifestPath string
|
ManifestPath string
|
||||||
LockPath string
|
LockPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// SessionWorkDir returns the work directory for one session.
|
// SessionWorkDir returns the work directory for one session.
|
||||||
@@ -27,17 +27,17 @@ func buildSessionPaths(workspaceRoot, sessionID string) SessionPaths {
|
|||||||
root := SessionWorkDir(workspaceRoot, sessionID)
|
root := SessionWorkDir(workspaceRoot, sessionID)
|
||||||
transcripts := filepath.Join(root, "transcripts")
|
transcripts := filepath.Join(root, "transcripts")
|
||||||
return SessionPaths{
|
return SessionPaths{
|
||||||
WorkspaceRoot: workspaceRoot,
|
WorkspaceRoot: workspaceRoot,
|
||||||
Root: root,
|
Root: root,
|
||||||
InputsDir: filepath.Join(root, "inputs"),
|
InputsDir: filepath.Join(root, "inputs"),
|
||||||
AudioDir: filepath.Join(root, "audio"),
|
AudioDir: filepath.Join(root, "audio"),
|
||||||
TranscriptsDir: transcripts,
|
TranscriptsDir: transcripts,
|
||||||
TranscriptsRawDir: filepath.Join(transcripts, "raw"),
|
TranscriptsRawDir: filepath.Join(transcripts, "raw"),
|
||||||
TranscriptsNormalizedDir: filepath.Join(transcripts, "normalized"),
|
TranscriptsTrimmedDir: filepath.Join(transcripts, "trimmed"),
|
||||||
ArtifactsDir: filepath.Join(root, "artifacts"),
|
ArtifactsDir: filepath.Join(root, "artifacts"),
|
||||||
ConfigDir: filepath.Join(root, "config"),
|
ConfigDir: filepath.Join(root, "config"),
|
||||||
LogsDir: filepath.Join(root, "logs"),
|
LogsDir: filepath.Join(root, "logs"),
|
||||||
ManifestPath: filepath.Join(root, "manifest.json"),
|
ManifestPath: filepath.Join(root, "manifest.json"),
|
||||||
LockPath: filepath.Join(root, ".lock"),
|
LockPath: filepath.Join(root, ".lock"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,9 +90,9 @@ func All() []Stage {
|
|||||||
return []Stage{
|
return []Stage{
|
||||||
prepareStage{},
|
prepareStage{},
|
||||||
transcribeStage{},
|
transcribeStage{},
|
||||||
placeholderStage{name: "normalize"},
|
|
||||||
mergeStage{},
|
mergeStage{},
|
||||||
polishStage{},
|
polishStage{},
|
||||||
|
placeholderStage{name: "trim"},
|
||||||
analyzeStage{},
|
analyzeStage{},
|
||||||
placeholderStage{name: "archive"},
|
placeholderStage{name: "archive"},
|
||||||
placeholderStage{name: "notify"},
|
placeholderStage{name: "notify"},
|
||||||
|
|||||||
Reference in New Issue
Block a user