The production pipeline answers how StoryMatrix moves a generation request through nine ordered stages and resumes after a checkpoint.

🧭 Fixed stage order

GenerateStoryUseCase constructs StoryProductionPipeline with this exact order (src/storymatrix/application/use_cases/generate_story.py):

#Stage classImplementationReads from contextWrites to contextSkip flag or condition
1CharacterMappingStageapplication/production/stages/character_mapping_stage.pyrequest, optional story_plan, provider configurationcharacter_mapNone
2StoryPlanStageapplication/production/stages/story_plan_stage.pyrequest, character_map, temp_pathstory_plan, story_data, and a refreshed character_map when new names appearNone
3StoryWritingStageapplication/production/stages/story_writing_stage.pyoutput_path, request, story_plan, story_data, character_mapstorySTORY.md at output_path selects author-provided ingestion
4ImagePromptGenerationStageapplication/production/stages/image_prompt_generation_stage.pystory, story_plan, story_dataenhanced_image_promptsProvider failure clears prompts and returns the context
5GenerateMediaAssetsStageapplication/production/stages/generate_media_assets.pystory, request, timeline, temp_path, output_path, enhanced_image_promptsgenerated_audio_segments, artifacts, and asset_durationsrequest.skip_steps["image"] skips image generation; request.sfx and request.ambient_sounds select audio content
6TimelineGenerationStageapplication/production/stages/timeline_generation_stage.pystory, character_map, temp_path, request, generated_audio_segmentstimelineRequires story and character_map
7AssembleAudioStageapplication/production/stages/assemble_audio.pystory, timeline, generated_audio_segments, artifacts, requestFinal audio artifacts and audio metadataMissing timeline or audio segments returns the context without assembly
8FinalizeProductionStageapplication/production/stages/finalize_production.pystory, final-audio artifacts, output_path, artifacts_pathMaster files, stem metadata, and final output metadataMissing final-audio artifact returns the context
9CleanupStageapplication/production/stages/cleanup_stage.pytemp_path, artifacts_path, request.keep_temp_filesFilesystem cleanup statekeep_temp_files and path-safety checks skip deletion

πŸ”— Execution flow

flowchart LR
    A[CharacterMappingStage] --> B[StoryPlanStage]
    B --> C[StoryWritingStage]
    C --> D[ImagePromptGenerationStage]
    D --> E[GenerateMediaAssetsStage]
    E --> F[TimelineGenerationStage]
    F --> G[AssembleAudioStage]
    G --> H[FinalizeProductionStage]
    H --> I[CleanupStage]

πŸ“¦ StoryProductionContext

StoryProductionContext is a Pydantic BaseModel with ConfigDict(arbitrary_types_allowed=True), allowing domain objects and filesystem paths to pass between stages (src/storymatrix/application/production/context.py).

FieldTypeRole
requestGenerateStoryRequestOriginal generation options
storyStory | NoneDomain story aggregate
story_planStoryPlan | NoneCrew-generated planning result
story_dataStoryData | NoneStructured story data
timelineAgenticTimeline | NoneAudio timeline
generated_audio_segmentslist[dict[str, Any]] | NoneGenerated audio segment records
artifacts_pathPathArtifact working directory
temp_pathPathTemporary working directory
output_pathPath | NoneOutput directory
generation_timestampfloat | NoneGeneration start timestamp
characterslist[Character] | NoneCharacter collection
character_mapdict | NoneCharacter-to-voice mapping
enhanced_image_promptslist[dict[str, str]] | NoneCrew-enhanced image prompts
metadatadict[str, Any]Arbitrary stage metadata
artifactslist[Artifact]Produced artifact records
asset_durationsdict[str, float]Duration metadata keyed by asset
completed_stageslist[str]Completed stage class names
stage_checkpointsdict[str, datetime]Completion timestamps by stage
pipeline_statedict[str, Any]Additional resumability state

πŸ’Ύ Checkpointing and resume

Checkpointing is enabled by default on StoryProductionPipeline. After each stage returns a non-None context, the pipeline marks the stage class name complete and writes <artifacts_path>/checkpoint.json; if a stage raises, the exception path writes the current context checkpoint before re-raising (src/storymatrix/application/production/pipeline.py).

The JSON checkpoint contains completed_stages, ISO-formatted stage_checkpoints, pipeline_state, generation_timestamp, artifacts_count, and metadata (src/storymatrix/application/production/context.py). Loading restores completed stage names, parses checkpoint timestamps, restores pipeline state, and merges saved metadata.

--resume reaches the use case request as request.resume and is passed to StoryProductionPipeline.run(resume=...) (src/storymatrix/application/use_cases/generate_story.py). When resume is true, the pipeline attempts to load the checkpoint, computes get_next_stages(all_stage_names) when the context already has completed stages, and logs that result; the dispatch loop does not consume that computed list. Instead, it always iterates the original nine-stage list in order and skips each stage whose class name is already present in completed_stages via is_stage_completed; the first absent class name is therefore the next stage that runs (src/storymatrix/application/production/pipeline.py, src/storymatrix/application/production/context.py). If checkpoint loading fails or no checkpoint exists on a fresh context, completed_stages remains at its fresh default of an empty list, so execution starts at CharacterMappingStage; loading does not clear an existing completed-stage set (src/storymatrix/application/production/context.py).

πŸ—‚οΈ Output contract

The output root is out/, selected by config/models.py:AppSettings.output_dir. Finalization organizes the master output and artifacts below that root (src/storymatrix/application/production/stages/finalize_production.py). The artifact layout is read from the code because no pipeline run has completed in this checkout.

⚠️ Known break in the timeline stage

LLMAgenticTimelineAdapter.direct_audio_timeline calls logger in six response-parsing call sites, but llm_agentic_timeline_adapter.py does not import or define that symbol (src/storymatrix/infrastructure/adapters/timeline/llm_agentic_timeline_adapter.py). The resulting NameError enters the deterministic-timeline fallback, which absorbs the failure. The agentic response path therefore never runs successfully while the timeline stage still returns the deterministic fallback as if successful. The fix is to import the project logger before those calls. Track this defect at index > b3.