diff --git a/backend/tools/review_structured_acceptance_gate.py b/backend/tools/review_structured_acceptance_gate.py index 0095a689..bb189783 100644 --- a/backend/tools/review_structured_acceptance_gate.py +++ b/backend/tools/review_structured_acceptance_gate.py @@ -911,17 +911,19 @@ def build_trend_rows( return trend_rows -def load_previous_snapshot() -> Optional[Dict[str, object]]: - latest_path = BASELINE_ROOT / "latest-summary.json" +def load_previous_snapshot(baseline_root: Path = BASELINE_ROOT) -> Optional[Dict[str, object]]: + latest_path = baseline_root / "latest-summary.json" if not latest_path.exists(): return None return json.loads(latest_path.read_text(encoding="utf-8")) -def persist_baseline_history(summary: Dict[str, object]) -> None: - BASELINE_ROOT.mkdir(parents=True, exist_ok=True) - BASELINE_SNAPSHOTS_DIR.mkdir(parents=True, exist_ok=True) - previous_snapshot = load_previous_snapshot() +def persist_baseline_history(summary: Dict[str, object], baseline_root: Path = BASELINE_ROOT) -> None: + snapshots_dir = baseline_root / "snapshots" + history_jsonl = baseline_root / "review-structured-baseline-history.jsonl" + baseline_root.mkdir(parents=True, exist_ok=True) + snapshots_dir.mkdir(parents=True, exist_ok=True) + previous_snapshot = load_previous_snapshot(baseline_root) generated_at = str(summary["generated_at"]) safe_stamp = generated_at.replace(":", "-").replace(".", "-") @@ -937,7 +939,7 @@ def persist_baseline_history(summary: Dict[str, object]) -> None: "sample_inventory": summary.get("sample_inventory") or [], } - snapshot_path = BASELINE_SNAPSHOTS_DIR / f"{safe_stamp}-review-structured-baseline-snapshot.json" + snapshot_path = snapshots_dir / f"{safe_stamp}-review-structured-baseline-snapshot.json" snapshot_path.write_text(json.dumps(snapshot_payload, ensure_ascii=False, indent=2), encoding="utf-8") history_row = { @@ -948,18 +950,18 @@ def persist_baseline_history(summary: Dict[str, object]) -> None: "field_metric_count": len(summary.get("field_baseline") or []), "relationship_metric_count": len(summary.get("relationship_baseline") or []), } - with BASELINE_HISTORY_JSONL.open("a", encoding="utf-8") as fh: + with history_jsonl.open("a", encoding="utf-8") as fh: fh.write(json.dumps(history_row, ensure_ascii=False) + "\n") - latest_path = BASELINE_ROOT / "latest-summary.json" + latest_path = baseline_root / "latest-summary.json" latest_path.write_text(json.dumps(snapshot_payload, ensure_ascii=False, indent=2), encoding="utf-8") - write_csv(BASELINE_ROOT / "latest-field-baseline.csv", summary.get("field_baseline") or []) - write_csv(BASELINE_ROOT / "latest-relationship-baseline.csv", summary.get("relationship_baseline") or []) - write_csv(BASELINE_ROOT / "latest-field-baseline-by-contract.csv", summary.get("field_baseline_by_contract") or []) - write_csv(BASELINE_ROOT / "latest-field-baseline-by-batch.csv", summary.get("field_baseline_by_batch") or []) - write_csv(BASELINE_ROOT / "latest-relationship-baseline-by-type.csv", summary.get("relationship_baseline_by_type") or []) - write_csv(BASELINE_ROOT / "latest-sample-inventory.csv", summary.get("sample_inventory") or []) + write_csv(baseline_root / "latest-field-baseline.csv", summary.get("field_baseline") or []) + write_csv(baseline_root / "latest-relationship-baseline.csv", summary.get("relationship_baseline") or []) + write_csv(baseline_root / "latest-field-baseline-by-contract.csv", summary.get("field_baseline_by_contract") or []) + write_csv(baseline_root / "latest-field-baseline-by-batch.csv", summary.get("field_baseline_by_batch") or []) + write_csv(baseline_root / "latest-relationship-baseline-by-type.csv", summary.get("relationship_baseline_by_type") or []) + write_csv(baseline_root / "latest-sample-inventory.csv", summary.get("sample_inventory") or []) field_trend_rows = build_trend_rows( summary.get("field_baseline") or [], @@ -992,11 +994,11 @@ def persist_baseline_history(summary: Dict[str, object]) -> None: ["presence_accuracy", "confidence_accuracy"], ) - write_csv(BASELINE_ROOT / "baseline-trend-overall.csv", field_trend_rows) - write_csv(BASELINE_ROOT / "baseline-trend-relationship-overall.csv", relationship_trend_rows) - write_csv(BASELINE_ROOT / "baseline-trend-by-contract.csv", contract_trend_rows) - write_csv(BASELINE_ROOT / "baseline-trend-by-batch.csv", batch_trend_rows) - write_csv(BASELINE_ROOT / "baseline-trend-by-relationship-type.csv", relationship_type_trend_rows) + write_csv(baseline_root / "baseline-trend-overall.csv", field_trend_rows) + write_csv(baseline_root / "baseline-trend-relationship-overall.csv", relationship_trend_rows) + write_csv(baseline_root / "baseline-trend-by-contract.csv", contract_trend_rows) + write_csv(baseline_root / "baseline-trend-by-batch.csv", batch_trend_rows) + write_csv(baseline_root / "baseline-trend-by-relationship-type.csv", relationship_type_trend_rows) dashboard_html = build_dashboard_html( summary, summary.get("field_baseline") or [], @@ -1005,9 +1007,9 @@ def persist_baseline_history(summary: Dict[str, object]) -> None: summary.get("field_baseline_by_batch") or [], summary.get("relationship_baseline_by_type") or [], ) - (BASELINE_ROOT / "baseline-trend-dashboard.html").write_text(dashboard_html, encoding="utf-8") + (baseline_root / "baseline-trend-dashboard.html").write_text(dashboard_html, encoding="utf-8") - trend_summary_md = BASELINE_ROOT / "baseline-trend-summary.md" + trend_summary_md = baseline_root / "baseline-trend-summary.md" lines = [ "# Structured Baseline Trend Summary", "", @@ -1088,9 +1090,11 @@ def main() -> int: parser.add_argument("--api-base", required=True) parser.add_argument("--artifact-dir", required=True) parser.add_argument("--password", default="123456") + parser.add_argument("--baseline-root", default=str(BASELINE_ROOT)) args = parser.parse_args() artifact_dir = Path(args.artifact_dir) + baseline_root = Path(args.baseline_root) summary = run_gate(api_base=args.api_base.rstrip("/"), artifact_dir=artifact_dir, password=args.password) summary_path = artifact_dir / "review-structured-acceptance-summary.json" summary_path.write_text(json.dumps(summary, ensure_ascii=False, indent=2), encoding="utf-8") @@ -1124,7 +1128,7 @@ def main() -> int: ), encoding="utf-8", ) - persist_baseline_history(summary) + persist_baseline_history(summary, baseline_root=baseline_root) print(f"REVIEW_STRUCTURED_ACCEPTANCE_{summary['status']} {artifact_dir}") return 0 if summary["status"] == "PASS" else 1 diff --git a/scripts/run-review-structured-acceptance-gate.ps1 b/scripts/run-review-structured-acceptance-gate.ps1 index 4d68abe8..ec9ac60f 100644 --- a/scripts/run-review-structured-acceptance-gate.ps1 +++ b/scripts/run-review-structured-acceptance-gate.ps1 @@ -66,7 +66,8 @@ if ($gitStatus) { $failed = @($checks | Where-Object { $_.required -and $_.status -eq "FAIL" }) if ($failed.Count -eq 0) { $logPath = Join-Path $artifactDir "review-structured-acceptance-gate.log" - & $pythonPath $toolPath --api-base $ApiUrl --artifact-dir $artifactDir --password $Password 2>&1 | Tee-Object -FilePath $logPath + $baselineRoot = Join-Path $artifactDir "baselines" + & $pythonPath $toolPath --api-base $ApiUrl --artifact-dir $artifactDir --password $Password --baseline-root $baselineRoot 2>&1 | Tee-Object -FilePath $logPath if ($LASTEXITCODE -eq 0) { Add-Check -Label "structured acceptance gate" -Status "PASS" -Detail "Structured acceptance gate passed" } else {