2929from .gate import AcceptanceGate
3030from .loader import read_json
3131from .loader import stable_config_hash
32+ from .report import RunArtifactPaths
3233from .report import build_report
3334from .report import compute_case_deltas
3435from .report import finalize_run_artifacts
3536from .report import persist_writeback_journal
3637from .report import persist_writeback_outcome
3738from .report import prepare_run_artifacts
39+ from .report import reserve_run_artifacts
40+ from .report import validate_unique_round_ids
3841from .schemas import CandidatePrompt
3942from .schemas import CostSummary
4043from .schemas import EvalResult
@@ -119,7 +122,8 @@ async def execute_pipeline(
119122 {"train" : request .train_path , "validation" : request .validation_path },
120123 context = "train and validation evalset paths" ,
121124 )
122- run_root = _claim_run_directory (request .output_dir , run_id = run_id )
125+ artifact_paths = reserve_run_artifacts (request .output_dir , run_id = run_id )
126+ run_root = artifact_paths .temp_run_dir
123127
124128 input_snapshots = _snapshot_pipeline_inputs (request , run_id = run_id )
125129 try :
@@ -130,6 +134,7 @@ async def execute_pipeline(
130134 started = started ,
131135 run_id = run_id ,
132136 run_root = run_root ,
137+ artifact_paths = artifact_paths ,
133138 input_snapshots = input_snapshots ,
134139 )
135140 except BaseException as primary_error :
@@ -172,6 +177,7 @@ async def _execute_with_snapshots(
172177 started : float ,
173178 run_id : str ,
174179 run_root : Path ,
180+ artifact_paths : RunArtifactPaths ,
175181 input_snapshots : _InputSnapshots ,
176182) -> OptimizationReport :
177183 prompt_snapshot = snapshot_prompt_files (request .target_prompt_paths )
@@ -483,6 +489,7 @@ async def _execute_with_snapshots(
483489 gate_decisions = gate_decisions ,
484490 selected_candidate = selected_candidate ,
485491 audit = audit ,
492+ baseline_prompts = dict (baseline_prompts ),
486493 rounds = optimization .rounds ,
487494 cost_summary = cost_summary ,
488495 writeback = provisional_writeback ,
@@ -492,7 +499,7 @@ async def _execute_with_snapshots(
492499 prompt_snapshot ,
493500 context = "immediately before preparing run artifacts" ,
494501 )
495- artifact_paths = prepare_run_artifacts (report , request . output_dir )
502+ prepare_run_artifacts (report , artifact_paths )
496503 if selected_candidate is None or not request .update_source :
497504 terminal_journal = _terminal_journal (
498505 writeback_journal ,
@@ -509,22 +516,17 @@ async def _execute_with_snapshots(
509516 request = request ,
510517 )
511518 persist_writeback_outcome (final_report , artifact_paths )
512- _verify_terminal_writeback_integrity (
513- prompt_snapshot ,
514- expected_hashes = prompt_snapshot .hashes (),
515- context = "immediately before finalizing no-write run" ,
516- artifact_paths = artifact_paths ,
517- journal = terminal_journal ,
518- request = request ,
519- )
520- finalize_run_artifacts (final_report , artifact_paths )
521- _verify_terminal_writeback_integrity (
522- prompt_snapshot ,
523- expected_hashes = prompt_snapshot .hashes (),
524- context = "immediately before returning no-write run" ,
525- artifact_paths = artifact_paths ,
526- journal = terminal_journal ,
527- request = request ,
519+ finalize_run_artifacts (
520+ final_report ,
521+ artifact_paths ,
522+ before_publish = lambda : _verify_terminal_writeback_integrity (
523+ prompt_snapshot ,
524+ expected_hashes = prompt_snapshot .hashes (),
525+ context = "immediately before publishing no-write run" ,
526+ artifact_paths = artifact_paths ,
527+ journal = terminal_journal ,
528+ request = request ,
529+ ),
528530 )
529531 return final_report
530532
@@ -553,22 +555,17 @@ async def _execute_with_snapshots(
553555 request = request ,
554556 )
555557 persist_writeback_outcome (final_report , artifact_paths )
556- _verify_terminal_writeback_integrity (
557- prompt_snapshot ,
558- expected_hashes = prompt_snapshot .hashes (),
559- context = "immediately before finalizing input-drift run" ,
560- artifact_paths = artifact_paths ,
561- journal = final_journal ,
562- request = request ,
563- )
564- finalize_run_artifacts (final_report , artifact_paths )
565- _verify_terminal_writeback_integrity (
566- prompt_snapshot ,
567- expected_hashes = prompt_snapshot .hashes (),
568- context = "immediately before returning input-drift run" ,
569- artifact_paths = artifact_paths ,
570- journal = final_journal ,
571- request = request ,
558+ finalize_run_artifacts (
559+ final_report ,
560+ artifact_paths ,
561+ before_publish = lambda : _verify_terminal_writeback_integrity (
562+ prompt_snapshot ,
563+ expected_hashes = prompt_snapshot .hashes (),
564+ context = "immediately before publishing input-drift run" ,
565+ artifact_paths = artifact_paths ,
566+ journal = final_journal ,
567+ request = request ,
568+ ),
572569 )
573570 return final_report
574571
@@ -637,22 +634,17 @@ async def _execute_with_snapshots(
637634 request = request ,
638635 )
639636 persist_writeback_outcome (final_report , artifact_paths )
640- _verify_terminal_writeback_integrity (
641- prompt_snapshot ,
642- expected_hashes = terminal_prompt_hashes ,
643- context = "immediately before finalizing writeback run" ,
644- artifact_paths = artifact_paths ,
645- journal = final_journal ,
646- request = request ,
647- )
648- finalize_run_artifacts (final_report , artifact_paths )
649- _verify_terminal_writeback_integrity (
650- prompt_snapshot ,
651- expected_hashes = terminal_prompt_hashes ,
652- context = "immediately before returning writeback run" ,
653- artifact_paths = artifact_paths ,
654- journal = final_journal ,
655- request = request ,
637+ finalize_run_artifacts (
638+ final_report ,
639+ artifact_paths ,
640+ before_publish = lambda : _verify_terminal_writeback_integrity (
641+ prompt_snapshot ,
642+ expected_hashes = terminal_prompt_hashes ,
643+ context = "immediately before publishing writeback run" ,
644+ artifact_paths = artifact_paths ,
645+ journal = final_journal ,
646+ request = request ,
647+ ),
656648 )
657649 return final_report
658650
@@ -711,17 +703,6 @@ def _snapshot_pipeline_inputs(request: PipelineRequest, *, run_id: str) -> _Inpu
711703 return _InputSnapshots (snapshots )
712704
713705
714- def _claim_run_directory (output_dir : str | Path , * , run_id : str ) -> Path :
715- runs_root = Path (output_dir ) / "runs"
716- runs_root .mkdir (parents = True , exist_ok = True )
717- run_root = runs_root / run_id
718- try :
719- run_root .mkdir ()
720- except FileExistsError as error :
721- raise ValueError (f"run_id { run_id !r} already exists in { runs_root } " ) from error
722- return run_root
723-
724-
725706def _verify_snapshot_integrity (
726707 snapshots : _InputSnapshots ,
727708 * requested_roles : str ,
@@ -1335,6 +1316,7 @@ def _validate_optimization_result(result: OptimizationResult) -> None:
13351316 round_record .cost ,
13361317 context = f"optimization round { round_record .round_id } cost" ,
13371318 )
1319+ validate_unique_round_ids (result .rounds )
13381320 if not isinstance (result .raw_summary , dict ):
13391321 raise ValueError ("optimization raw_summary must be an object" )
13401322 _validate_nested_numbers (result .raw_summary , context = "optimization raw_summary" )
0 commit comments