diff --git a/internal/app/object_store.go b/internal/app/object_store.go index 0c23b3a..f44e723 100644 --- a/internal/app/object_store.go +++ b/internal/app/object_store.go @@ -13,7 +13,15 @@ func newCommandObjectStore(ctx context.Context, cfg *config.Config, logger *slog if _, err := loadSecretsFromConfig(cfg, logger); err != nil { return nil, fmt.Errorf("load secrets from files: %w", err) } - store, err := newObjectStoreFromConfigFn(ctx, cfg) + return initializeObjectStoreBackend(ctx, cfg, newObjectStoreFromConfigFn) +} + +func initializeObjectStoreBackend( + ctx context.Context, + cfg *config.Config, + factory func(context.Context, *config.Config) (storage.ObjectStore, error), +) (storage.ObjectStore, error) { + store, err := factory(ctx, cfg) if err != nil { return nil, fmt.Errorf("initialize object store backend: %w", err) } diff --git a/internal/app/operator_helpers_test.go b/internal/app/operator_helpers_test.go index 51cb4de..3f6e3da 100644 --- a/internal/app/operator_helpers_test.go +++ b/internal/app/operator_helpers_test.go @@ -1272,8 +1272,6 @@ func TestExecutePublishLoadsRemoteLocks(t *testing.T) { fake := &storage.FakeBackend{} lockKey := artifacts.S3SessionLocksKey(artifacts.S3SessionPrefix("dnd", "sample-campaign", "2026-05-03")) fake.SeedObject(storage.FakeObject{Key: lockKey, Data: []byte("locks:\n - source: narratio.transcript.final_trimmed\n reason: remote review\n")}) - var storeInitCalls int - restoreAppConfigTestGlobals(t, fake, &storeInitCalls, []string{sessionPath}) workRoot := filepath.Join(workspaceRoot, "work", "sample-campaign", "2026-05-03") mustWriteTestFile(t, filepath.Join(workRoot, "transcripts", "final.trimmed.json"), `{"segments":[]}`) @@ -1304,10 +1302,25 @@ func TestExecutePublishLoadsRemoteLocks(t *testing.T) { } var stdout bytes.Buffer - var stderr bytes.Buffer - code := Execute([]string{"run-stage", "publish", "2026-05-03", "--config", pipelinePath, "--campaign-file", campaignPath, "--session", sessionPath, "--force"}, &stdout, &stderr) - if code != 0 { - t.Fatalf("exit code = %d, want 0; stderr=%q", code, stderr.String()) + var storeInitCalls int + err = runStageWithPipelineExecutor( + context.Background(), + []string{"publish", "2026-05-03", "--config", pipelinePath, "--campaign-file", campaignPath, "--session", sessionPath, "--force"}, + &stdout, + func(ctx context.Context, cfg *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) { + return executePlanWithDependencies(ctx, cfg, plan, opts, invocationDependencies{ + newObjectStore: func(context.Context, *config.Config) (storage.ObjectStore, error) { + storeInitCalls++ + return fake, nil + }, + }) + }, + ) + if err != nil { + t.Fatalf("runStageWithPipelineExecutor() error = %v", err) + } + if storeInitCalls != 1 { + t.Fatalf("object store initialization calls = %d, want 1", storeInitCalls) } publishedKey := artifacts.S3PublishedOutputKey(artifacts.S3SessionPrefix("dnd", "sample-campaign", "2026-05-03"), "transcripts/final.trimmed.json") if _, ok := fake.Objects[publishedKey]; ok { diff --git a/internal/app/restore_workflow_test.go b/internal/app/restore_workflow_test.go index 2edb8e8..782af15 100644 --- a/internal/app/restore_workflow_test.go +++ b/internal/app/restore_workflow_test.go @@ -206,21 +206,18 @@ previous_session_id: 2026-04-26 mustReadEquals(t, filepath.Join(sessionRoot, "previous", "artifacts", "session_recap.md"), "# previous recap\n") scriptoriumFake := &scriptorium.FakeRunner{} - origObjectStoreFn := newObjectStoreFromConfigFn objectStoreConstructed := false - t.Cleanup(func() { - newObjectStoreFromConfigFn = origObjectStoreFn - }) executor := func(ctx context.Context, cfg *config.Config, plan BoundedPlan, opts RunOptions) (*RunSummary, error) { if opts.Env == nil { opts.Env = &Env{} } opts.Env.Scriptorium = scriptoriumFake - return executePlan(ctx, cfg, plan, opts) - } - newObjectStoreFromConfigFn = func(context.Context, *config.Config) (storage.ObjectStore, error) { - objectStoreConstructed = true - return nil, context.Canceled + return executePlanWithDependencies(ctx, cfg, plan, opts, invocationDependencies{ + newObjectStore: func(context.Context, *config.Config) (storage.ObjectStore, error) { + objectStoreConstructed = true + return nil, context.Canceled + }, + }) } stdout.Reset() diff --git a/internal/app/runner_dependencies.go b/internal/app/runner_dependencies.go index 4eafad7..59cfc1b 100644 --- a/internal/app/runner_dependencies.go +++ b/internal/app/runner_dependencies.go @@ -52,7 +52,7 @@ func (dependencies invocationDependencies) normalized() invocationDependencies { } if dependencies.newObjectStore == nil { dependencies.newObjectStore = func(ctx context.Context, cfg *config.Config) (storage.ObjectStore, error) { - return newCommandObjectStore(ctx, cfg, nil) + return initializeObjectStoreBackend(ctx, cfg, storage.NewObjectStoreFromConfig) } } if dependencies.loadEffectiveLocks == nil {