|
11 | 11 | RunMetadata, |
12 | 12 | append_event, |
13 | 13 | create_run_paths, |
| 14 | + write_quality_report, |
14 | 15 | write_result, |
15 | 16 | write_run_metadata, |
16 | 17 | ) |
17 | 18 | from runtime.preflight import run_preflight |
| 19 | +from runtime.quality_checks import evaluate_run_quality |
18 | 20 | from runtime.release_policy import DEFAULT_RELEASE_POLICY, ReleasePolicy |
19 | 21 | from runtime.runner import EXPERIMENTAL_PROTOCOLS, SUPPORTED_PROTOCOLS, run_protocol |
20 | 22 | from runtime.session_config import build_session_config, load_mouse_info, load_session_template |
@@ -88,6 +90,11 @@ def parse_args() -> argparse.Namespace: |
88 | 90 | action="store_true", |
89 | 91 | help="Skip run artifact validation (debug-only escape hatch).", |
90 | 92 | ) |
| 93 | + parser.add_argument( |
| 94 | + "--no-validate-quality", |
| 95 | + action="store_true", |
| 96 | + help="Skip semantic run quality checks (debug-only escape hatch).", |
| 97 | + ) |
91 | 98 | return parser.parse_args() |
92 | 99 |
|
93 | 100 |
|
@@ -120,9 +127,15 @@ def resolve_release_policy(require_release_tag: bool) -> ReleasePolicy: |
120 | 127 | return replace(DEFAULT_RELEASE_POLICY, require_release_tag_in_production=True) |
121 | 128 |
|
122 | 129 |
|
123 | | -def validate_runtime_options(run_mode: str, no_validate_artifacts: bool) -> None: |
| 130 | +def validate_runtime_options( |
| 131 | + run_mode: str, |
| 132 | + no_validate_artifacts: bool, |
| 133 | + no_validate_quality: bool, |
| 134 | +) -> None: |
124 | 135 | if run_mode == "production" and no_validate_artifacts: |
125 | 136 | raise ValueError("Artifact validation cannot be disabled in production mode.") |
| 137 | + if run_mode == "production" and no_validate_quality: |
| 138 | + raise ValueError("Run quality validation cannot be disabled in production mode.") |
126 | 139 |
|
127 | 140 |
|
128 | 141 | def main() -> int: |
@@ -156,7 +169,11 @@ def main() -> int: |
156 | 169 |
|
157 | 170 | require_confirmation = True if args.run_mode == "production" else (not args.yes) |
158 | 171 | release_policy = resolve_release_policy(require_release_tag=args.require_release_tag) |
159 | | - validate_runtime_options(run_mode=args.run_mode, no_validate_artifacts=args.no_validate_artifacts) |
| 172 | + validate_runtime_options( |
| 173 | + run_mode=args.run_mode, |
| 174 | + no_validate_artifacts=args.no_validate_artifacts, |
| 175 | + no_validate_quality=args.no_validate_quality, |
| 176 | + ) |
160 | 177 |
|
161 | 178 | git_state = run_preflight( |
162 | 179 | repo_root=repo_root, |
@@ -199,6 +216,17 @@ def emit_event(event_type: str, payload: dict[str, object]) -> None: |
199 | 216 | joined = "\n".join(f"- {error}" for error in validation_errors) |
200 | 217 | raise RuntimeError(f"Run artifact validation failed:\n{joined}") |
201 | 218 |
|
| 219 | + quality_report = evaluate_run_quality(run_paths.run_dir) |
| 220 | + write_quality_report(run_paths.quality_report_path, quality_report) |
| 221 | + if not args.no_validate_quality and quality_report["status"] == "FAIL": |
| 222 | + quality_errors = [ |
| 223 | + finding["message"] |
| 224 | + for finding in quality_report.get("findings", []) |
| 225 | + if finding.get("level") == "error" |
| 226 | + ] |
| 227 | + joined = "\n".join(f"- {error}" for error in quality_errors) |
| 228 | + raise RuntimeError(f"Run quality validation failed:\n{joined}") |
| 229 | + |
202 | 230 | print(f"Run complete: {session.run_id}") |
203 | 231 | print(f"Protocol: {session.protocol}") |
204 | 232 | print(f"Output directory: {run_paths.run_dir}") |
|
0 commit comments