Spaces:
Sleeping
Sleeping
| """Run plan.md verification steps 1-5 with UTF-8 evidence capture. | |
| Writes one fresh log per step to launch_contract.resolve_scratch_dir(). | |
| Exits non-zero on the first failed assertion. | |
| """ | |
| from __future__ import annotations | |
| import io | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| ROOT = Path(__file__).resolve().parent.parent | |
| if str(ROOT) not in sys.path: | |
| sys.path.insert(0, str(ROOT)) | |
| from launch_contract import ( # noqa: E402 | |
| check_cli_output, | |
| check_license, | |
| check_positioning, | |
| check_readme, | |
| check_source_claims, | |
| clean_stale_scratch_artifacts, | |
| resolve_scratch_dir, | |
| ) | |
| CYCLE_SLOW_LITERAL = "Cycle time: 2.0 µs" | |
| MANGLED_MICRO = "┬Á" | |
| CLI_MARKERS = ( | |
| "QEC-Playground Simulation Results", | |
| "Total decoding time", | |
| "Conditional wait reduction", | |
| ) | |
| EVIDENCE_FILES = ( | |
| "core_direct.log", | |
| "cli1.log", | |
| "cli2.log", | |
| "cli_verify.log", | |
| "cli_slow.log", | |
| "pytest.log", | |
| "license.log", | |
| "positioning.log", | |
| "docs_verify.log", | |
| "sensitivity.log", | |
| "changed_files.log", | |
| "pytest_full.log", | |
| "gating_manifest.log", | |
| ) | |
| def _write(path: Path, text: str) -> None: | |
| path.write_text(text, encoding="utf-8") | |
| def _fail(step: str, message: str) -> int: | |
| print(f"GATING_FAIL step={step}: {message}", file=sys.stderr) | |
| return 1 | |
| def step1_core_direct(scratch: Path) -> tuple[str, int] | None: | |
| code = """ | |
| from core.simulator import run_simulation | |
| res = run_simulation( | |
| processor_count=4, | |
| cycle_time_us=1.0, | |
| speculation_accuracy=0.9, | |
| decoder_latency_rounds=2, | |
| ordering_strategy='shallow_first', | |
| seed=42, | |
| ) | |
| print('spec_wait=', res['speculative']['average_conditional_wait_time_us']) | |
| print('nonspec_wait=', res['non_speculative']['average_conditional_wait_time_us']) | |
| print('max_decoders=', res['speculative']['max_concurrent_decoders']) | |
| print('metrics_keys=', list(res['speculative'].keys())) | |
| print('completed=', res.get('completed')) | |
| """ | |
| proc = subprocess.run( | |
| [sys.executable, "-c", code], | |
| cwd=ROOT, | |
| capture_output=True, | |
| text=True, | |
| encoding="utf-8", | |
| ) | |
| log = proc.stdout | |
| if proc.stderr: | |
| log = f"{log}\n{proc.stderr}" if log else proc.stderr | |
| _write(scratch / "core_direct.log", log) | |
| if proc.returncode != 0: | |
| return _fail("1", f"core_direct exit {proc.returncode}") | |
| if "spec_wait=" not in log or "nonspec_wait=" not in log: | |
| return _fail("1", "missing spec_wait/nonspec_wait lines") | |
| if "completed= True" not in log and "completed=True" not in log.replace(" ", ""): | |
| return _fail("1", "completed not True") | |
| for key in ( | |
| "total_decoding_time_us", | |
| "average_window_backlog", | |
| "average_conditional_wait_time_us", | |
| "ui_window_count", | |
| "max_concurrent_decoders", | |
| ): | |
| if key not in log: | |
| return _fail("1", f"metrics_keys missing {key}") | |
| spec_line = next((ln for ln in log.splitlines() if ln.startswith("spec_wait=")), "") | |
| nonspec_line = next((ln for ln in log.splitlines() if ln.startswith("nonspec_wait=")), "") | |
| max_dec_line = next((ln for ln in log.splitlines() if ln.startswith("max_decoders=")), "") | |
| try: | |
| spec_wait = float(spec_line.split("=", 1)[1].strip()) | |
| nonspec_wait = float(nonspec_line.split("=", 1)[1].strip()) | |
| max_dec = float(max_dec_line.split("=", 1)[1].strip()) | |
| except (IndexError, ValueError): | |
| return _fail("1", "could not parse wait times or max_decoders") | |
| if spec_wait <= 0 or nonspec_wait <= 0: | |
| return _fail("1", f"non-positive conditional wait spec={spec_wait} nonspec={nonspec_wait}") | |
| if max_dec < 0: | |
| return _fail("1", f"invalid max_decoders {max_dec}") | |
| try: | |
| from core.simulator import run_simulation | |
| res = run_simulation(seed=42, schedule_id="three_t_injection") | |
| spec_rt = float(res["speculative"]["total_decoding_time_us"]) | |
| nonspec_rt = float(res["non_speculative"]["total_decoding_time_us"]) | |
| if spec_rt > nonspec_rt: | |
| return _fail("1", f"spec_runtime {spec_rt} > nonspec_runtime {nonspec_rt}") | |
| except Exception as exc: | |
| return _fail("1", f"runtime check failed: {exc}") | |
| return None | |
| def step2_cli(scratch: Path) -> int | None: | |
| def run_app(*extra: str) -> subprocess.CompletedProcess[str]: | |
| return subprocess.run( | |
| [sys.executable, "app.py", *extra], | |
| cwd=ROOT, | |
| capture_output=True, | |
| text=True, | |
| encoding="utf-8", | |
| ) | |
| for name in ("cli1", "cli2"): | |
| proc = run_app() | |
| log = proc.stdout | |
| if proc.stderr: | |
| log = f"{log}\n{proc.stderr}" if log else proc.stderr | |
| _write(scratch / f"{name}.log", log) | |
| if proc.returncode != 0: | |
| return _fail("2", f"{name} exit {proc.returncode}") | |
| cli1 = (scratch / "cli1.log").read_text(encoding="utf-8") | |
| cli2 = (scratch / "cli2.log").read_text(encoding="utf-8") | |
| if cli1 != cli2: | |
| return _fail("2", "cli1.log != cli2.log") | |
| _write(scratch / "cli_verify.log", "CLI_REPEAT_OK\n") | |
| slow = run_app("--cycle-time-us", "2", "--processors", "4", "--schedule", "three_t_injection") | |
| slow_log = slow.stdout | |
| if slow.stderr: | |
| slow_log = f"{slow_log}\n{slow.stderr}" if slow_log else slow.stderr | |
| _write(scratch / "cli_slow.log", slow_log) | |
| if slow.returncode != 0: | |
| return _fail("2", f"cli_slow exit {slow.returncode}") | |
| for label, text in (("cli1", cli1), ("cli2", cli2), ("cli_slow", slow_log)): | |
| checks = check_cli_output(text) | |
| if not all(checks.values()): | |
| return _fail("2", f"{label} CLI markers failed: {checks}") | |
| if not any(ch.isdigit() for ch in text): | |
| return _fail("2", f"{label} missing numeric values") | |
| if MANGLED_MICRO in slow_log: | |
| return _fail("2", "cli_slow has mangled micro sign (PowerShell encoding)") | |
| if CYCLE_SLOW_LITERAL not in slow_log: | |
| return _fail("2", f"cli_slow missing literal {CYCLE_SLOW_LITERAL!r}") | |
| return None | |
| def step3_pytest(scratch: Path) -> int | None: | |
| proc = subprocess.run( | |
| [ | |
| sys.executable, | |
| "-m", | |
| "pytest", | |
| "tests/test_swiper_sim.py", | |
| "tests/test_decoder.py", | |
| "tests/test_managers.py", | |
| "-q", | |
| "--tb=line", | |
| ], | |
| cwd=ROOT, | |
| capture_output=True, | |
| text=True, | |
| encoding="utf-8", | |
| ) | |
| _write(scratch / "pytest.log", proc.stdout) | |
| if proc.returncode != 0: | |
| err_tail = proc.stderr.strip().splitlines()[-3:] if proc.stderr else [] | |
| return _fail("3", f"pytest exit {proc.returncode}; stderr_tail={err_tail}") | |
| lines = [ln for ln in proc.stdout.splitlines() if ln.strip()] | |
| if not lines or " passed" not in lines[-1]: | |
| return _fail("3", f"pytest stdout does not end with passed summary; tail={lines[-3:]}") | |
| return None | |
| def step4_docs(scratch: Path) -> int | None: | |
| license_text = (ROOT / "LICENSE").read_text(encoding="utf-8") | |
| _write(scratch / "license.log", license_text) | |
| readme_text = (ROOT / "README.md").read_text(encoding="utf-8") | |
| spec_text = (ROOT / "spec.md").read_text(encoding="utf-8") | |
| buf = io.StringIO() | |
| print("license", check_license(), file=buf) | |
| print("readme", check_readme(readme_text), file=buf) | |
| print("spec_pos", check_positioning(spec_text), file=buf) | |
| print("source", check_source_claims(), file=buf) | |
| positioning_log = buf.getvalue() | |
| _write(scratch / "positioning.log", positioning_log) | |
| license_checks = check_license() | |
| readme_checks = check_readme(readme_text) | |
| spec_checks = check_positioning(spec_text) | |
| source_checks = check_source_claims() | |
| if not all(license_checks.values()): | |
| return _fail("4", f"license checks failed: {license_checks}") | |
| if not all(readme_checks.values()): | |
| return _fail("4", f"readme checks failed: {readme_checks}") | |
| if not all(spec_checks.values()): | |
| return _fail("4", f"spec_pos checks failed: {spec_checks}") | |
| if not all(source_checks.values()): | |
| return _fail("4", f"source checks failed: {source_checks}") | |
| proc = subprocess.run( | |
| [sys.executable, "scripts/docs_verify.py"], | |
| cwd=ROOT, | |
| capture_output=True, | |
| text=True, | |
| encoding="utf-8", | |
| ) | |
| docs_log = proc.stdout | |
| if proc.stderr: | |
| docs_log = f"{docs_log}\n{proc.stderr}" if docs_log else proc.stderr | |
| _write(scratch / "docs_verify.log", docs_log) | |
| if proc.returncode != 0: | |
| return _fail("4", f"docs_verify exit {proc.returncode}") | |
| if "DOCS_VERIFY_OK" not in docs_log: | |
| return _fail("4", "docs_verify missing DOCS_VERIFY_OK") | |
| return None | |
| def step5_sensitivity(scratch: Path) -> int | None: | |
| code = """ | |
| from core.simulator import run_simulation | |
| f = run_simulation(cycle_time_us=1.0, seed=42) | |
| s = run_simulation( | |
| cycle_time_us=2.0, | |
| processor_count=2, | |
| schedule_id='three_t_injection', | |
| seed=42, | |
| ) | |
| print( | |
| 'FAST', | |
| f['speculative']['average_conditional_wait_time_us'], | |
| f['non_speculative']['average_conditional_wait_time_us'], | |
| ) | |
| print( | |
| 'SLOW', | |
| s['speculative']['average_conditional_wait_time_us'], | |
| s['non_speculative']['average_conditional_wait_time_us'], | |
| ) | |
| print('SENSITIVITY_OK') | |
| """ | |
| proc = subprocess.run( | |
| [sys.executable, "-c", code], | |
| cwd=ROOT, | |
| capture_output=True, | |
| text=True, | |
| encoding="utf-8", | |
| ) | |
| log = proc.stdout | |
| if proc.stderr: | |
| log = f"{log}\n{proc.stderr}" if log else proc.stderr | |
| _write(scratch / "sensitivity.log", log) | |
| if proc.returncode != 0: | |
| return _fail("5", f"sensitivity exit {proc.returncode}") | |
| if "SENSITIVITY_OK" not in log: | |
| return _fail("5", "missing SENSITIVITY_OK") | |
| return None | |
| def _wipe_scratch(scratch: Path) -> None: | |
| """Remove every file in scratch so stale polluted logs cannot survive partial runs.""" | |
| if not scratch.exists(): | |
| return | |
| for path in scratch.iterdir(): | |
| if path.is_file(): | |
| path.unlink() | |
| def main() -> int: | |
| scratch = resolve_scratch_dir() | |
| scratch.mkdir(parents=True, exist_ok=True) | |
| clean_stale_scratch_artifacts(scratch) | |
| _wipe_scratch(scratch) | |
| _write( | |
| scratch / "gating_manifest.log", | |
| f"producer=scripts/verify_gating.py\nscratch={scratch}\nencoding=utf-8\n", | |
| ) | |
| for step_fn in (step1_core_direct, step2_cli, step3_pytest, step4_docs, step5_sensitivity): | |
| err = step_fn(scratch) | |
| if err is not None: | |
| return err | |
| changed_proc = subprocess.run( | |
| [sys.executable, "scripts/changed_files_report.py"], | |
| cwd=ROOT, | |
| capture_output=True, | |
| text=True, | |
| encoding="utf-8", | |
| ) | |
| _write(scratch / "changed_files.log", changed_proc.stdout) | |
| if changed_proc.returncode != 0: | |
| return _fail("changed_files", changed_proc.stderr or "changed_files_report failed") | |
| changed_section = changed_proc.stdout.split("DEVIATIONS:")[0] | |
| for line in changed_section.splitlines(): | |
| parts = line.split() | |
| if len(parts) >= 2 and parts[-1] == "cli.py": | |
| return _fail("changed_files", "cli.py must not appear in CHANGED_FILES section") | |
| if ".gating-evidence" in changed_proc.stdout: | |
| return _fail("changed_files", ".gating-evidence must not appear in CHANGED_FILES") | |
| if " D cli.py" in changed_proc.stdout or "\nD cli.py" in changed_proc.stdout: | |
| if "DEVIATIONS:" not in changed_proc.stdout or "cli.py" not in changed_proc.stdout: | |
| return _fail("changed_files", "cli.py delete must be tagged under DEVIATIONS") | |
| full_pytest = subprocess.run( | |
| [sys.executable, "-m", "pytest", "tests/", "-q", "--tb=line"], | |
| cwd=ROOT, | |
| capture_output=True, | |
| text=True, | |
| encoding="utf-8", | |
| ) | |
| _write(scratch / "pytest_full.log", full_pytest.stdout) | |
| if full_pytest.returncode != 0: | |
| return _fail("pytest_full", f"full suite exit {full_pytest.returncode}") | |
| full_lines = [ln for ln in full_pytest.stdout.splitlines() if ln.strip()] | |
| if not full_lines or "passed" not in full_lines[-1]: | |
| return _fail("pytest_full", f"unexpected pytest_full tail: {full_lines[-3:]}") | |
| print(f"GATING_OK evidence={scratch}") | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) |